其他分享
首页 > 其他分享> > 2019.08.23 日常总结

2019.08.23 日常总结

作者:互联网

洛谷P1993:

题意:

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

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

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

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

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

若某行输入为2 a b c,则加入边(b,a,-c)(a,b,0)

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

建图成功后,用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;
}

 

标签:2019.08,联通,23,int,农场,输出,村庄,分量,日常
来源: https://blog.csdn.net/ZHUYINGYE_123456/article/details/100044701