Day9 图论综合题

版权声明:https://blog.csdn.net/huashuimu2003 https://blog.csdn.net/huashuimu2003/article/details/87630718

A. 白银莲花池

题目

LUOGU 2411

代码

#include<bits/stdc++.h>
using namespace std;
const int maxn=35;
const int maxm=1e5+10;
const int dx[8]={1,2,2,1,-1,-2,-2,-1};
const int dy[8]={2,1,-1,-2,-2,-1,1,2};
template<typename T>inline void read(T &x)
{
    x=0;
    T f=1,ch=getchar();
    while (!isdigit(ch)) ch=getchar();
    if (ch=='-') f=-1, ch=getchar();
    while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar();
    x*=f;
}
int n,m,sx,sy,tx,ty;
char c[maxn][maxn];
int ver[maxm<<1][2],edge[maxm<<1],Next[maxm<<1],head[maxn][maxn],len;
inline void add(int x,int y)
{
	for (int i=0;i<8;++i)
	{
		int xx=x+dx[i],yy=y+dy[i];
		if (xx>0 && xx<=n && yy>0 && yy<=m)
		{
			if (c[xx][yy]=='0')
				ver[++len][0]=xx,ver[len][1]=yy,edge[len]=1,Next[len]=head[x][y],head[x][y]=len;
			else if (c[xx][yy]=='1' || c[xx][yy]=='4')
				ver[++len][0]=xx,ver[len][1]=yy,edge[len]=0,Next[len]=head[x][y],head[x][y]=len;
		}
	}
}
int dist[maxn][maxn],step[maxn][maxn];
bool vis[maxn][maxn];
long long ans[maxn][maxn];
inline void spfa()
{
	memset(dist,0x3f3f3f,sizeof(dist));
	memset(step,0x3f3f3f,sizeof(step));
	queue<pair<int,int> >q;
	dist[sx][sy]=0,step[sx][sy]=0,ans[sx][sy]=1;
	q.push(make_pair(sx,sy));
	while (!q.empty())
	{
		int ux=q.front().first,uy=q.front().second;
		q.pop();
		vis[ux][uy]=0;
		for (int i=head[ux][uy];i;i=Next[i])
		{
			int vx=ver[i][0],vy=ver[i][1];
			if (dist[vx][vy]>dist[ux][uy]+edge[i])
			{
				dist[vx][vy]=dist[ux][uy]+edge[i];
				step[vx][vy]=step[ux][uy]+1;
				ans[vx][vy]=ans[ux][uy];
				if (!vis[vx][vy]) q.push(make_pair(vx,vy)),vis[vx][vy]=1;
			}
			else if (dist[vx][vy]==dist[ux][uy]+edge[i])
			{
				if (step[vx][vy]>step[ux][uy]+1)
				{
					step[vx][vy]=step[ux][uy]+1;
					ans[vx][vy]=ans[ux][uy];
					if (!vis[vx][vy]) q.push(make_pair(vx,vy)),vis[vx][vy]=1;
				}
				else if (step[vx][vy]==step[ux][uy]+1)
					ans[vx][vy]+=ans[ux][uy];
			}
		}
	}
}
int main()
{
	freopen("silvlily.in","r",stdin);
	freopen("silvlily.out","w",stdout);
	read(n);read(m);
	for (int i=1;i<=n;++i)
		for (int j=1;j<=m;++j)
		{
			cin>>c[i][j];
			if (c[i][j]=='3') sx=i,sy=j;
			if (c[i][j]=='4') tx=i,ty=j;
		}
	for (int i=1;i<=n;++i)
		for (int j=1;j<=m;++j)//错误原因1
			if (c[i][j]!='2')
				add(i,j);
	spfa();
	if (dist[tx][ty]==1061109567)
		puts("-1");
	else
		printf("%d\n%d\n%lld",dist[tx][ty],step[tx][ty],ans[tx][ty]);
	return 0;
}

B. 跳楼机

题目

LUOGU 3403

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
template<typename T>inline void read(T &x)
{
    x=0;
    T f=1,ch=getchar();
    while (!isdigit(ch)) ch=getchar();
    if (ch=='-') f=-1, ch=getchar();
    while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar();
    x*=f;
}
int ver[maxn<<1],Next[maxn<<1],head[maxn],len;
ll edge[maxn<<1];
inline void add(int x,int y,ll z)
{
	ver[++len]=y,edge[len]=z,Next[len]=head[x],head[x]=len;
}
ll dist[maxn];
bool vis[maxn];
inline void spfa(int s)
{
	memset(dist,0x3f3f3f3f,sizeof(dist));
	memset(vis,0,sizeof(vis));
	queue<int>q;
//	dist[1%s]=1,vis[1%s]=1;
//	q.push(1%s);
	dist[1]=1,vis[1]=1;//一楼能到的mod x最小楼层数就是1了,所以dist[1]=1,zz的错误
	q.push(1);
	while (!q.empty())
	{
		int x=q.front();
		q.pop();
		vis[x]=0;
		for (int i=head[x];i;i=Next[i])
		{
			int y=ver[i];
			ll z=edge[i];
			if (dist[y]>dist[x]+z)
			{
				dist[y]=dist[x]+z;
				if (!vis[y]) q.push(y),vis[y]=1;
			}
		}
	}
}
int main()
{
	freopen("srwudi.in","r",stdin);
	freopen("srwudi.out","w",stdout);
	ll h;int x,y,z;
	read(h);read(x);read(y);read(z);
	if (x==1 || y==1 || z==1)
	{
		printf("%lld\n",h);
		exit(0);
	}
	for (int i=0;i<x;++i)
		add(i,(i+y)%x,y),add(i,(i+z)%x,z);
	spfa(1);
	ll ans=0;
	for (int i=0;i<x;++i)
		if (dist[i]<=h)
			ans+=(h-dist[i])/x+1;
	printf("%lld\n",ans);
	return 0;
}

C. [中山市选]生成树

题目

LUOGU 4821

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=2007;
template<typename T>inline void read(T &x)
{
    x=0;
    T f=1,ch=getchar();
    while (!isdigit(ch)) ch=getchar();
    if (ch=='-') f=-1, ch=getchar();
    while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar();
    x*=f;
}
inline ll Quick_mul(ll x,ll y)
{
	return ((x*y-(ll)(((long double)x*y+0.5)/mod)*mod)%mod+mod)%mod;
}
inline ll Quick_power(ll a,ll b)
{
	ll ans=1;
	while (b)
	{
		if (b&1)
			ans=Quick_mul(ans,a);
		a=Quick_mul(a,a);
		b>>=1;
	}
	return ans;
}
int main()
{
	freopen("data.in","r",stdin);
	freopen("data.out","w",stdout);
	int t;read(t);
	while (t--)
	{
		int n;read(n);
		if (n==1) puts("5");
		else
		{
			ll ans=Quick_power(5,n-1);
			printf("%lld\n",ans*n*4%mod);
		}
	}
	return 0;
}

D. 最小代价

题目

题目描述
给出一幅由n个点m条边构成的无向带权图。 其中有些点是黑点,其他点是白点。
现在每个白点都要与他距离最近的黑点通过最短路连接(如果有很多个黑点,可以选取其中任意一个),我们想要使得花费的代价最小。
请问这个最小代价是多少?
注意:最后选出的边保证每个白点到离它最近的黑点的距离仍然等于原图中的最短距离。
输入格式
第一行两个整数n,m;
第二行n 个整数,0表示白点,1 表示黑点;
接下来m 行,每行三个整数x,y,z,表示一条连接x和y 点,权值为z 的边。
输出格式
如果无解,输出impossible;
否则,输出最小代价。
样例数据
input
5 7
0 1 0 1 0
1 2 11
1 3 1
1 5 17
2 3 1
3 5 18
4 5 3
2 4 5
output
5
【样例解释】
选 2、4、6三条边
数据规模与约定
对30%的输入数据: 1≤n≤10, 1≤m≤20; 对100%的输入数据:1≤n≤100000,1≤m≤200000,1≤z≤1000000000
时间限制:1s1s
空间限制:256MB

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
template<typename T>inline void read(T &x)
{
    x=0;
    T f=1,ch=getchar();
    while (!isdigit(ch)) ch=getchar();
    if (ch=='-') f=-1, ch=getchar();
    while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar();
    x*=f;
}
struct Edge
{
	int x,y,z,Next,flag;
}e[maxn<<5];
int head[maxn],len,n,m,start;
inline void add(int x,int y,int z)
{
	e[++len].x=x,e[len].y=y,e[len].z=z,e[len].Next=head[x],e[len].flag=0,head[x]=len;
}
ll dist[maxn];
bool vis[maxn];
inline void spfa(int s)
{
	memset(dist,0x3f3f3f3f,sizeof(dist));
	memset(vis,0,sizeof(vis));
	queue<int>q;
	dist[s]=0,vis[s]=1;
	q.push(s);
	while (!q.empty())
	{
		int x=q.front();
		q.pop();
		vis[x]=0;
		for (int i=head[x];i;i=e[i].Next)
		{
			int y=e[i].y,z=e[i].z;
			if (dist[y]>dist[x]+1ll*z)
			{
				dist[y]=dist[x]+z;
				if (!vis[y]) q.push(y),vis[y]=1;
			}
		}
	}
}
int a[maxn];
inline void build()
{
	for (int x=1;x<=n;++x)
	{
		if (a[x]) continue;
		for (int i=head[x];i;i=e[i].Next)
		{
			int y=e[i].y,z=e[i].z;
			if (!y) continue;
			if (dist[y]+1ll*z==dist[x]) e[i].flag=1;
		}
	}
}
int fa[maxn];
inline int get(int x)
{
	if (fa[x]==x) return x;
	return fa[x]=get(fa[x]);
}
inline bool cmp(Edge a,Edge b)
{
	return a.z<b.z;
}
int main()
{
	freopen("minimum.in","r",stdin);
	freopen("minimum.out","w",stdout);
	read(n);read(m);
	for (int i=1;i<=n;++i)
		read(a[i]);
	for (int i=1;i<=m;++i)
	{
		int x,y,z;
		read(x);read(y);read(z);
		add(x,y,z);add(y,x,z);
	}
	for (int i=1;i<=n;++i)
	{
		if (a[i]) add(start,i,0),add(i,start,0);
		fa[i]=i;
	}
	spfa(start);
	build();
	sort(e+1,e+len+1,cmp);
	ll ans=0;
	int tot=0;
	for (int i=1;i<=len;++i)
	{
		if (!e[i].flag) continue;
		int x=get(e[i].x),y=get(e[i].y);
		if (x!=y)
		{
			fa[y]=x;
			ans+=1ll*e[i].z;
			++tot;
			if (tot==n-1) break;
		}
	}
	if (!ans)
		puts("impossible");
	else
		printf("%lld\n",ans);
	return 0;
}

E.追捕盗贼

题目

题目描述
  为了帮助警察抓住在逃的罪犯,你发明了一个新的计算机系统。
警察控制的区域有N个城市,城市之间有E条双向边连接,城市编号为1到N。
 警察经常想在罪犯从一个城市逃亡另一个城市的过程中抓住他。侦查员在仔细研究地图,以决定在哪个城市设置障碍,或者断掉某条路。
你的计算机系统必须回答以下两种问题:   
1、 如果连接城市G1和G2的路被封掉,罪犯能否从城市A逃到城市B?   
2、 如果城市C被封掉,罪犯能否从城市A逃到城市B?
输入格式
  输入第一行包含两个整数N和E(2<=N<=100000,1<=E<=500000),表示城市和边的数量。
  接下来E行,每行包含两个不同的整数Ai和Bi,表示城市Ai和Bi之间有一条边直接相连,任意两个城市之间最多只有一条边相连。  
 接下来一行包含一个整数Q(1<=Q<=300000),表示询问次数。
 接下来Q行,每行包含4个或5个整数,第一个数为1或2,表示询问问题的种类。  
如果问题种类是1,后面跟着4个整数A,B,G1,G2,如上描述表示询问如果G1和G2之间的路封掉罪犯能否从城市A逃到城市B,保证A和B不同,G1和G2之间一定存在路。   
如果问题种类是2,后面跟着三个整数A,B,C,三个数互不相同,表示询问如果封掉城市C,罪犯能否从城市A逃到城市B。   
输入数据保证一开始任意两个城市都可以相互到达。
输出格式
  每个询问输出一行“yes”或“no”。
样例数据
input
13 15
1 2
2 3
3 5
2 4
4 6
2 6
1 4
1 7
7 8
7 9
7 10
8 11
8 12
9 12
12 13
5
1 5 13 1 2
1 6 2 1 4
1 13 6 7 8
2 13 6 7
2 13 6 8
output
yes
yes
yes
no
yes
数据规模与约定
时间限制:1s1s
空间限制:256MB

代码

#include<bits/stdc++.h>
#define YES { printf("yes\n"); continue; }//YES表示联通
#define NO { printf("no\n"); continue; }//NO表示不联通
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;//表示某个A或B。tmp.first表示第几个操作,mtp.second表示是A(0)还是B(1)
const int maxn=1e5+10;
template<typename T>inline void read(T &x)
{
    x=0;
    T f=1,ch=getchar();
    while (!isdigit(ch)) ch=getchar();
    if (ch=='-') f=-1, ch=getchar();
    while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar();
    x*=f;
}
int A[maxn*3],B[maxn*3],C[maxn*3],D[maxn*3],ya[maxn*3],yb[maxn*3];
int ver[maxn<<5],Next[maxn<<5],head[maxn],len;
inline void add(int x,int y)
{
	ver[++len]=y,Next[len]=head[x],head[x]=len;
}
int dfn[maxn],low[maxn],id;
int fa[maxn],Q[maxn];
vector<int>b[2][maxn];//b[0][x]表示所有在点x的A的i(即它是第几个操作),b[1][x]表示在点x的B的i
vector<pii>belc[maxn];//bC[x]表示所有以点x为C的操作
inline int tarjan(int x)
{
	for (int j=0;j<=1;++j)//j=0时是A,j=1时使B
		while (!b[j][x].empty())//看看所有在点x的A或B
		{
			int i=b[j][x].back();
			if (dfn[C[i]])//必须要判断,因为dfn[C[i]]>0了C[i]才有可能是x的祖先
				belc[C[i]].push_back(make_pair(i,j));
			b[j][x].pop_back();
		}
	dfn[x]=low[x]=++id;
	for (int i=head[x];i;i=Next[i])
	{
		int y=ver[i];
		if (y!=fa[x])//求双联通分量不能重复经过某条边
		{
			if (!dfn[y])
			{
				fa[y]=x;
				tarjan(y);
				low[x]=min(low[x],low[y]);
				while (!belc[x].empty())//清理x的栈
				{
					pii tmp=belc[x].back();
					tmp.second?yb[tmp.first]=y:ya[tmp.first]=y;//t.se=1则表示t是个B,否则是个A
					belc[x].pop_back();
				}
			}
			else
				low[x]=min(low[x],dfn[y]);
		}
	}
	Q[x]=id;//计算x的子树范围
}
inline bool in(int x,int y)//判断点x是否在点y的子树中
{
	return dfn[y]<=dfn[x] && dfn[x]<=Q[y];
}
int type[maxn*3];
int main()
{
	freopen("data.in","r",stdin);
	freopen("data.out","w",stdout);
	int n,m;
	read(n);read(m);
	for (int i=1;i<=m;++i)
	{
		int x,y;
		read(x);read(y);
		add(x,y);add(y,x);
	}
	int q;
	read(q);
	for (int i=1;i<=q;++i)
	{
		read(type[i]);read(A[i]);read(B[i]);read(C[i]);
		if (type[i]==1) read(D[i]);
		else
			b[0][A[i]].push_back(i),b[1][B[i]].push_back(i);//将每个A、B存进图中
	}
	for (int i=1;i<=n;++i)
		if (!dfn[i]) tarjan(i);
	for (int i=1;i<=q;++i)
	{
		if (type[i]==1)
		{
			if (C[i]==D[i]) YES;
			if (dfn[C[i]]>dfn[D[i]]) swap(C[i],D[i]);
			if (low[D[i]]==dfn[D[i]])
			{
				if (in(A[i],D[i]) && !in(B[i],D[i])) NO;
				if (in(B[i],D[i]) && !in(A[i],D[i])) NO;
			}
			YES;
		}
		if (ya[i]==yb[i]) YES;
		if (ya[i] && low[ya[i]]>=dfn[C[i]]) NO;
		if (yb[i] && low[yb[i]]>=dfn[C[i]]) NO;
		YES;
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/huashuimu2003/article/details/87630718
今日推荐