2019.08.23 日常总结

白昼怎懂夜的黑 提交于 2019-11-28 08:24:35

洛谷P1993:

题意:

小K在MC里面建立很多很多的农场,总共n个,以至于他自己都忘记了每个农场中种植作物的具体数量了,他只记得一些含糊的信息(共m个),以下列三种形式描述:

  • 农场a比农场b至少多种植了c个单位的作物,
  • 农场a比农场b至多多种植了c个单位的作物,
  • 农场a与农场b种植的作物数一样多。

但是,由于小K的记忆有些偏差,所以他想要知道存不存在一种情况,使得农场的种植作物数量与他记忆中的所有信息吻合。

思路:画了下划线的三句话提示我们这题要用差分约束系统

记val[a]表示第a个农场中了几枝花,从a到b连一条权值为c的边表示

,则

若某行输入为1 a b c,则加入边

若某行输入为2 a b c,则加入边

若某行输入为3 a b,则加入边

建图成功后,用spfa跑一遍最长路,若有正环,输出No,否则输出Yes

提示:全图不一定强联通,所以每个强联通分量都要跑一遍最长路,若每个强联通分量存在最长路,就输出No

 #include <bits/stdc++.h> using namespace std; const int N=10100; struct node{ 	int next,to,w; }e[N<<1];int h[N],tot; inline void add(int a,int b,int c){ 	e[++tot]=(node){h[a],b,c};h[a]=tot; } int d[N];bool v[N],vis[N]; //d表示最长路的长度,v和vis表示是否访问过 bool spfa(int u){ 	vis[u]=v[u]=true;register int i; 	for(i=h[u];i;i=e[i].next){ 		register int to=e[i].to; 		if (d[u]+e[i].w>d[to]){ 		//别把>写成<了 			if (v[to]) return true; 			else{ 				d[to]=d[u]+e[i].w; 				if (spfa(to)) return true; 			} 		} 	} 	v[u]=false;return false; 	//千万别修改vis!!! } //用dfs版spfa判断有无正环 int n,m,opt,a,b,c,i; int main(){ 	freopen("t1.in","r",stdin); 	memset(d,128,sizeof(d)); 	scanf("%d%d",&n,&m); 	for(i=1;i<=m;i++){ 		scanf("%d%d%d",&opt,&a,&b); 		switch(opt){ 			case 1:scanf("%d",&c);add(a,b,c);break; 			case 2:scanf("%d",&c);add(b,a,-c);add(a,b,0);break; 			default:add(a,b,0);add(b,a,0);break; 			//用switch-case的童鞋,别忘了break 		} 	} 	for(i=1;i<=n;i++) 	if (!vis[i]){ 		d[i]=0; 		if (spfa(i)){ 			printf("No"); 			return 0; 		} 	} 	printf("Yes"); 	return 0; }

洛谷P1726:

题意:在幻想乡,上白泽慧音是以知识渊博闻名的老师。春雪异变导致人间之里的很多道路都被大雪堵塞,使有的学生不能顺利地到达慧音所在的村庄。因此慧音决定换一个能够聚集最多人数的村庄作为新的教学地点。人间之里由N个村庄(编号为1..N)和M条道路组成,道路分为两种一种为单向通行的,一种为双向通行的,分别用1和2来标记。如果存在由村庄A到达村庄B的通路,那么我们认为可以从村庄A到达村庄B,记为(A,B)。当(A,B)和(B,A)同时满足时,我们认为A,B是绝对连通的,记为<A,B>。绝对连通区域是指一个村庄的集合,在这个集合中任意两个村庄X,Y都满足<X,Y>。现在你的任务是,找出最大的绝对连通区域,并将这个绝对连通区域的村庄按编号依次输出。若存在两个最大的,输出字典序最小的,比如当存在1,3,4和2,5,6这两个最大连通区域时,输出的是1,3,4。

思路:题意就是让我们找出含顶点个数最多的强联通分量,既然是找强联通分量,肯定要用tarjan算法了,在处理每个点属于哪个强联通分量时,顺便求出每个强联通分量有多少个顶点在内,最后结合所有信息输出即可。

 #include <bits/stdc++.h> using namespace std; const int N=5010; const int M=50100; struct node{ 	int next,to; }e[M<<1];int h[N],tot; //注意e要开到M*2,而不是M inline void add(int a,int b){ 	e[++tot]=(node){h[a],b};h[a]=tot; } int dfn[N],low[N],dfscnt; int Stack[N],stack_top; int belong[N],col,num[N]; void tarjan(int u){//稍有改动的tarjan模板 	low[u]=dfn[u]=++dfscnt; 	Stack[++stack_top]=u; 	for(int i=h[u];i;i=e[i].next){ 		register int v=e[i].to; 		if (!dfn[v]){ 			tarjan(v); 			low[u]=min(low[u],low[v]); 		} 		else if (!belong[v]) 		low[u]=min(low[u],dfn[v]); 	} 	if (low[u]==dfn[u]){ 		belong[u]=++col;num[col]=1;//别忘了这句啊 		while (Stack[stack_top]!=u){ 			int v=Stack[stack_top]; 			belong[v]=col;--stack_top; 			num[col]++;//记录每个强联通分量所含顶点个数 		} 		--stack_top;//别忘了把u弹出栈哦 	} } int maxn,ans,i,n,m,x,y,t; int main(){ 	freopen("t1.in","r",stdin); 	scanf("%d%d",&n,&m); 	for(i=1;i<=m;i++){ 		scanf("%d%d%d",&x,&y,&t); 		add(x,y);if (t==2) add(y,x); 		//建图,注意处理好有向图和无向图 	} 	for(i=1;i<=n;i++) 	if (!dfn[i]) tarjan(i); 	//tarjan算法模板 	for(i=1;i<=col;i++) 	maxn=max(maxn,num[i]); 	//求所有强联通分量所含顶点个数最大值 	printf("%d",maxn); 	for(i=1;i<=n;i++) 	//从小到大枚举,保证字典序最小 	if (num[belong[i]]==maxn){ 		printf("\n%d",i); 		for(int j=i+1;j<=n;j++) 		if (belong[i]==belong[j]) 		printf(" %d",j);break; 	} 	return 0; }

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!