zoukankan      html  css  js  c++  java
  • BZOJ 1797 最小割

    Description

    A,B两个国家正在交战,其中A国的物资运输网中有(N)个中转站,(M)条单向道路。设其中第(i) ((1 le i le M))条道路连接了(v_{i},u_{i})两个中转站,那么中转站(v_{i})可以通过该道路到达(u_{i})中转站,如果切断这条道路,需要代价(c_{i})。现在B国想找出一个路径切断方案,使中转站(s)不能到达中转站(t),并且切断路径的代价之和最小。 小可可一眼就看出,这是一个求最小割的问题。但爱思考的小可可并不局限于此。现在他对每条单向道路提出两个问题: 问题一:是否存在一个最小代价路径切断方案,其中该道路被切断? 问题二:是否对任何一个最小代价路径切断方案,都有该道路被切断? 现在请你回答这两个问题。

    Input

    第一行有(4)个正整数,依次为(N,M,s)(t)。第(2)行到第((M+1))行每行(3)个正 整数(v,u,c)表示(v)中转站到(u)中转站之间有单向道路相连,单向道路的起点是(v), 终点是(u),切断它的代价是(c(1 le c le 100000))。 注意:两个中转站之间可能有多条道路直接相连。 同一行相邻两数之间可能有一个或多个空格。

    Output

    对每条单向边,按输入顺序,依次输出一行,包含两个非(0)(1)的整数,分别表示对问题一和问题二的回答(其中输出(1)表示是,输出(0)表示否)。 同一行相邻两数之间用一个空格隔开,每行开头和末尾没有多余空格。

    Sample Input

    6 7 1 6
    1 2 3
    1 3 2
    2 4 4
    2 5 1
    3 5 5
    4 6 2
    5 6 3

    Sample Output

    1 0
    1 0
    0 0
    1 0
    0 0
    1 0
    1 0

    HINT

    设第((i+1))行输入的边为(i)号边,那么(lbrace 1,2 brace,lbrace 6,7 brace,lbrace 2,4,6 brace)是仅有的三个最小代价切割方案。它们的并是(lbrace 1,2,4,6,7 brace),交是 (emptyset)

    测试数据规模如下表所示
    数据编号 (N) (M) 数据编号 (N) (M)
    (1) (10) (50) (6) (1000) (20000)
    (2) (20) (200) (7) (1000) (40000)
    (3) (200) (2000) (8) (2000) (50000)
    (4) (200) (2000) (9) (3000) (60000)
    (5) (1000) (20000) (10) (4000) (60000)

    此题的做法十分巧妙。
    首先求最小割,直接跑网络流。紧接着在残留网络上进行tarjan缩点。
    然后,对每条边进行询问:若该边已经满流,且两个端点并未在同一个强联通分量内部,则该店最小割集中的边(若在以强联通分量的内部,割掉此边无影响);若两个端点一个在(S)集中,一个在(T)集中,则该边一定在最小割集中(割掉此边后(S)(T)不联通)。

    #include<cstring>
    #include<iostream>
    #include<queue>
    #include<cstdio>
    #include<cstdlib>
    #include<stack>
    using namespace std;
    
    #define inf (1<<29)
    #define maxn 4010
    #define maxm 60010
    int toit[maxm*2],side[maxn],nd[maxn],next[maxm*2];
    int cap[maxm*2],cur[maxn],id[maxn],d[maxn],pre[maxn],cnt = 1;
    int n,m,source,sink,tot,all,dfn[maxn],low[maxn]; bool in[maxn];
    stack <int> S;
    
    inline int read()
    {
        int x = 0,f = 1; char ch = getchar();
        while(ch < '0' || ch > '9'){ if(ch == '-') f=-1; ch=getchar(); }
        while(ch >= '0' && ch <= '9'){ x = x * 10 + ch - '0'; ch = getchar(); }
        return x * f;
    }
    
    inline void add(int a,int b,int c)
    {
    	next[++cnt] = side[a]; side[a] = cnt;
    	toit[cnt] = b; cap[cnt] = c;
    }
    
    inline void ins(int a,int b,int c) { add(a,b,c); add(b,a,0); }
    
    inline void bfs()
    {
    	queue <int> team; int now,i;
    	memcpy(cur,side,4*(n+4));
    	team.push(sink); d[sink] = 1; in[sink] = true;
    	while (!team.empty())
    	{
    		now = team.front(); team.pop();
    		nd[d[now]]++;
    		for (i = side[now];i;i = next[i])
    			if (cap[i^1] && !in[toit[i]])
    				in[toit[i]] = true,d[toit[i]] = d[now] + 1,team.push(toit[i]);
    	}
    }
    
    inline void isap()
    {
    	bfs();
    	int res = 0,now = source,ca = inf,i;
    	while (d[source] <= n)
    	{
    		if (now == sink)
    		{
    			while (now != source)
    			{
    				cap[pre[now]] -= ca; cap[pre[now]^1] += ca;
    				now = toit[pre[now]^1];
    			}
    			res += ca;
    			ca = inf;
    		}
    		bool flag = false;
    		for (i = cur[now];i;i = next[i])
    			if (cap[i] && d[toit[i]] == d[now] - 1)
    			{
    				cur[now] = pre[toit[i]] = i;
    				ca = min(ca,cap[i]);
    				now = toit[i];
    				flag = true;
    				break;
    			}
    		if (flag) continue;
    		int arg = n;
    		if (!--nd[d[now]]) break;
    		for (i = side[now];i;i = next[i])
    			if (cap[i] && d[toit[i]] < arg) arg = d[toit[i]];
    		++nd[d[now] = arg + 1]; cur[now] = side[now];
    		if (now != source) now = toit[pre[now] ^ 1];
    	}
    	return;
    }
    
    inline void dfs(int now)
    {
    	low[now] = dfn[now] = ++tot;
    	S.push(now);
    	for (int i = side[now];i;i = next[i])
    		if (cap[i] && !in[toit[i]])
    		{
    			if (!dfn[toit[i]]) dfs(toit[i]);
    			low[now] = min(low[now],low[toit[i]]);
    		}
    	if (low[now] == dfn[now])
    	{
    		++all;
    		while (S.top() != now)  id[S.top()] = all,in[S.top()] = true,S.pop();
    		id[S.top()] = all; in[S.top()] = true; S.pop();
    	}
    }
    
    int main()
    {
    	freopen("1797.in","r",stdin);
    	freopen("1797.out","w",stdout);
    	n = read(); m = read(); source = read(); sink = read();
    	while (m--)
    	{
    		int a = read(),b = read(),c = read();
    		ins(a,b,c);
    	}
    	isap();
    	memset(in,false,n+2);
    	for (int i = 1;i <= n;++i) if (!dfn[i]) dfs(i);
    	for (int i = 2;i <= cnt;i += 2)
    	{
    		if (!cap[i])
    		{
    			if (id[toit[i]] != id[toit[i^1]]) printf("1 ");
    			else printf("0 ");
    			if (id[toit[i]] == id[source] &&id[toit[i^1]] == id[sink]) putchar('1');
    			else if (id[toit[i]] == id[sink] &&id[toit[i^1]] == id[source]) putchar('1');
    			else putchar('0');
    		}
    		else printf("0 0");
    		putchar('
    ');
    	}
    	fclose(stdin); fclose(stdout);
    	return 0;
    }
    
  • 相关阅读:
    LiveGBS接入LiveQing流媒体服务实现摄像头云端录像和和直播以及大屏展示
    摄像头网络直播方案LiveGBS部署问题 使GB28181实现无插件web直播
    Linux 查看磁盘读写速度IO使用情况
    安防监控摄像头接入云端实现直播、录像和大屏展示
    H265摄像头如何实现网页直播
    解决RTMP推送时间戳问题引起HLS切片不均匀导致手机浏览器播放卡顿的问题
    H5实现无插件视频监控按需直播
    LiveQing视频云平台部署实践
    将RTSP网络摄像机进行网页和微信直播的方案
    Android虚拟机运行问题之小结
  • 原文地址:https://www.cnblogs.com/mmlz/p/4325817.html
Copyright © 2011-2022 走看看