zoukankan      html  css  js  c++  java
  • 「图论」第4章 强连通分量课堂过关

    「图论」第4章 强连通分量课堂过关

    A. 【例题1】有向图缩点

    题目

    代码

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <queue>
    using namespace std;
    #define N 10010
    #define M 100010
    int read() {
    	int re = 0;
    	bool sig = 0;
    	char c = getchar();
    	while(c < '0' || c > '9') {
    		if(c == '-') 
    			sig = 1;
    		c = getchar();
    	}
    	while(c >= '0' && c <= '9')
    		re = (re << 1) + (re << 3) + c - '0' , c = getchar();
    	return sig ? -re : re;
    }
    struct node {
    	int to , nxt;
    }ed[2][M];
    int head[2][N];
    void addedge(int id , int u , int v) {
    	static int cnt[2];
    	node *e = ed[id];
    	int *h = head[id];
    	int c = ++cnt[id];
    	e[c].to = v , e[c].nxt = h[u] , h[u] = c;
    	return;
    }
    
    int n , m;
    int val[N];
    int dfn[N] , low[N]; 
    int stack[N] , top;
    int col[N];
    int sum[N] ;
    int tot;
    
    int maxv[N];
    int ind[N];
    void Tarjan(int x) {
    	static int Time = 0;
    	dfn[x] = low[x] = ++Time;
    	stack[++top] = x;
    	for(int i = head[0][x] ; i ; i = ed[0][i].nxt) {
    		int to = ed[0][i].to;
    		if(!dfn[to]) {
    			Tarjan(to);
    			if(low[to] < low[x])
    				low[x] = low[to];
    		}
    		else if(col[to] == 0 && low[x] > low[to])
    			low[x] = low[to];
    	}
    	if(dfn[x] == low[x]) {
    		col[x] = ++tot;
    		sum[tot] += val[x];
    		while(stack[top] != x)
    			sum[tot] += val[stack[top]] , col[stack[top]] = tot , --top;
    		top--;
    	}
    }
    int main() {
    	n = read() , m = read();
    	for(int i = 1 ; i <= n ; i++)
    		val[i] = read();
    	for(int i = 1 ; i <= m ; i++) {
    		int u = read() , v = read();
    		addedge(0 , u , v);
    	}
    	
    	for(int i = 1 ; i <= n ; i++)
    		if(dfn[i] == 0)
    			Tarjan(i);
    	
    	for(int i = 1 ; i <= n ; i++)
    		for(int j = head[0][i] ; j ; j = ed[0][j].nxt) {
    			int u = col[i] , v = col[ed[0][j].to];
    			if(u != v) {
    				addedge(1 , u , v);
    				++ind[v];
    			}
    		}
    	
    	queue <int> q;
    	for(int i = 1 ; i <= tot ; i++)
    		if(ind[i] == 0){
    			maxv[i] = sum[i];
    			q.push(i);
    		}	
    	while(!q.empty()) {
    		int u = q.front();
    		q.pop();
    		for(int i= head[1][u] ; i ; i = ed[1][i].nxt) {
    			int v = ed[1][i].to;
    			if(maxv[u] + sum[v] > sum[v])
    				sum[v] = maxv[u] + sum[v];
    			--ind[v];
    			if(ind[u] == 0)
    				q.push(v);
    		}
    	}
    	int ans = 0;
    	for(int i = 1 ; i <= tot ; i++)
    		if(ans < maxv[i])
    			ans = maxv[i];
    	cout << ans; 
    	return 0;
    }
    

    B. 【例题2】受欢迎的牛

    题目

    思路

    按喜欢关系建图,跑一边tarjan,若生成的DAG中同时存在多个出度为0的点,则这些点一定不能互相到达,答案为0,否则,出度为0的点代表的原图强连通块的点即为明星.

    代码

    #include <iostream>
    #include <cstdio>
    #define N 10010
    #define M 100010
    using namespace std;
    int read() {
    	int re = 0;
    	bool sig = 0;
    	char c = getchar();
    	while(c < '0' || c > '9') {
    		if(c == '-') 
    			sig = 1;
    		c = getchar();
    	}
    	while(c >= '0' && c <= '9')
    		re = (re << 1) + (re << 3) + c - '0' , c = getchar();
    	return sig ? -re : re;
    }
    
    struct node{
    	int to , nxt;
    }ed[M];
    int head[N];
    void addedge(int u , int v) {
    	static int cnt = 0;
    	++cnt;
    	ed[cnt].nxt = head[u] , ed[cnt].to = v , head[u] = cnt;
    }
    
    int n , m;
    int n2;
    int dfn[N] , low[N];
    int col[N] , w[N];
    int stac[N] , top;
    void tarjan(int x) {
    	static int Time = 0;
    	stac[++top] = x;
    	dfn[x] = low[x] = ++Time;
    	for(int i = head[x] ; i ; i = ed[i].nxt) {
    		int to = ed[i].to;
    		if(dfn[to] == 0) {
    			tarjan(to);
    			if(low[to] < low[x])
    				low[x] = low[to];
    		}
    		else if(col[to] == 0)
    			if(low[to] < low[x])
    				low[x] = low[to];
    	}
    	if(dfn[x] == low[x]) {
    		++n2;
    		col[x] = n2;
    		++w[n2];
    		while(stac[top] != x) {
    			col[stac[top]] = n2;
    			++w[n2];
    			--top;
    		}
    		--top;
    	}
    }
    int out[N];
    int main() {
    	n = read();
    	m = read();
    	for(int i = 1 ; i <= m ; i++) {
    		int u = read() , v = read();
    		addedge(u , v);
    	}
    	for(int i = 1 ; i <= n ; i++) 
    		if(dfn[i] == 0)
    			tarjan(i);
    	for(int i = 1 ; i <= n ; i++)
    		for(int j = head[i] ; j ; j = ed[j].nxt) {
    			int u = col[i] , v = col[ed[j].to];
    			if(u == v)continue;
    			++out[u];
    		}
    	int k = -1;
    	for(int i = 1 ; i <= n2 ; i++) {
    		if(out[i] == 0) {
    			if(k == -1)	k = i;
    			else {
    				cout << 0;
    				return 0;
    			}
    		}
    	}
    	cout << w[k];
    	return 0;
    } 
    

    D. 【例题4】恒星的亮度

    题目

    思路

    首先,这题用到差分约束,没学的先学

    鉴于恒星亮度为整数,我们转换一下题目所给的关系:

    [egin{cases} A=Bqquadqquad &Age B and Bge A\ A < B &B ge A+1\ A ge B & A ge B\ A > B & A ge B+1\ A le B & B ge A end{cases} ]

    这样,原关系就只剩下(ge)了.根据差分约束思想,若(Age B+val)就从(B)(A)连一条权值为(val),从每个入度为0的点出发跑一边最长路,距离即亮度, 若出现正环,则说明有(Age B ,Bge C , C > A)的错误关系,输出-1.

    问题是,怎么判断正环呢?SPFA?必TLE!

    看到这题边权只有0,1两种情况,不难想到,当一个强连通块内存在一条正权边时,必有正环,输出-1

    剩下的,交给拓扑DP即可

    代码

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <queue>
    #include <cstring>
    using namespace std;
    int read() {
    	int re = 0;
    	char c = getchar();
    	while(c < '0' || c > '9') c = getchar();
    	while(c >= '0' && c <= '9')
    		re = (re << 1) + (re << 3) + c - '0',
    		c = getchar();
    	return re;
    }
    #define N 100010
    #define M 200010
    struct node {
    	int to , nxt , val;
    }ed[M * 2];
    int HEAD[2][N];
    int *head;
    
    void addedge(int u , int v , int val) {
    	static int cnt = 0;
    	++cnt;
    	ed[cnt].nxt = head[u] , ed[cnt].to = v , ed[cnt].val = val , head[u] = cnt;
    }
    
    int n , m , n2;
    int dfn[N] , low[N] , col[N] , w[N];
    int stac[N] , top;
    int dist[N];
    void tarjan(int x) {
    	static int Time = 0;
    	dfn[x] = low[x] = ++Time;
    	stac[++top] = x;
    	for(int j = 1 ; j >= 0 ; j--)
    		for(int i = head[x] ; i ; i = ed[i].nxt) {
    			if(ed[j].val != j)	continue;
    			int to = ed[i].to;
    			if(dfn[to] == 0) {
    				tarjan(to );
    				if(low[to] < low[x])
    					low[x] = low[to];
    			}
    			else if(col[to] == 0) {
    				if(low[to] < low[x])
    					low[x] = low[to];
    			}
    		}
    	if(dfn[x] == low[x]) {
    		col[x] = ++n2;
    		while(x != stac[top]) {
    			col[stac[top]] = n2;
    			--top;
    		}
    		--top;
    	}
    }
    
    int ind[N];
    int main() {
    	n = read() , m = read();
    	head = HEAD[0];
    	for(int i = 1 ; i <= m ; i++) {
    		int T = read();
    		int u = read() , v = read();
    		switch(T) {
    			case 1 :
    				addedge(u , v , 0);
    				addedge(v , u , 0);
    				break;
    			case 2 :
    				addedge(u , v , 1); 
    				break;
    			case 3 :
    				addedge(v , u , 0);
    				break;
    			case 4 :
    				addedge(v , u , 1);
    				break;
    			case 5 :
    				addedge(u , v , 0);
    				break;
    		}
    	}/*
    	for(int i = 1 ; i <= n ; i++) {
    		cout << i << ":	";
    		for(int j = head[i] ; j ; j = ed[j].nxt)
    			cout << ed[j].to << ',' << ed[j].val << ' ';
    		cout << endl;
    	}*/
    	for(int i = 1 ; i <= n ; i++)
    		if(dfn[i] == 0)
    			tarjan(i);
    	head = HEAD[1];
    	for(int i = 1 ; i <= n ; i++)
    		for(int j = HEAD[0][i] ; j ; j = ed[j].nxt) {
    			int u = col[i] , v = col[ed[j].to];
    			if(u == v) {
    				if(ed[j].val > 0) {
    					cout << -1;
    					return 0;
    				}
    				continue;
    			} 
    			++ind[v];
    			addedge(u , v , ed[j].val);
    		}
    		
    	queue <int> q;
    	memset(dist , 0 , sizeof(dist));
    	for(int i = 1 ; i <= n2 ; i++)
    		if(ind[i] == 0) {
    			dist[i] = 1;
    			q.push(i);
    		}
    	while(!q.empty()) {
    		int k = q.front();
    		q.pop();
    		for(int i = head[k] ; i ; i = ed[i].nxt) {
    			int to = ed[i].to;
    			if(--ind[to] == 0)
    				q.push(to);
    			if(dist[k] + ed[i].val > dist[to])
    				dist[to] = dist[k] + ed[i].val;
    		}
    	}
    	long long ans = 0;
    	for(int i = 1 ; i <= n ; i++)
    		ans += dist[col[i]];
    	cout << ans;
    	return 0;
    } 
    
  • 相关阅读:
    不得不说微信之怪现状
    新手运营如何做广告位投放
    网络营销人员如何培养创新技能
    GoDaddy开通中文客服电话,沟通不再是问题
    为zblog FCKeditor编辑器添加设置字体格式h1 h2功能
    真实手机访问本地电脑网站失败的原因
    数据库简总
    简单总结
    GUI图形用户界面学习
    集合框架
  • 原文地址:https://www.cnblogs.com/dream1024/p/14728804.html
Copyright © 2011-2022 走看看