zoukankan      html  css  js  c++  java
  • poj 1637 Sightseeing tour【最大流+欧拉路】

    参考:https://www.cnblogs.com/kuangbin/p/3537525.html
    这篇讲的挺好的
    首先分清欧拉路和欧拉环:
    欧拉路:图中经过每条边一次且仅一次的路径,要求只有两个点的出入度之差为奇数,这两个点即为欧拉路的起点和终点
    欧拉环:图中经过每条边一次且仅一次的环,要求全部点的出入度之差为偶数
    这道题中要判定的是欧拉路。首先看是否满足“只有两个点的出入度之差为奇数”这个条件,可以发现尽管有没有定向的边,但是出入的之差的奇偶是不变的;假设一条从i出发的边变向为到达i,那么点i的入度+1出度-1,差的奇偶性不变。
    判定可以用网络流来做:s向所有差>0的点连流量为差/2的边,所有差<0的边向t连流量为差/2的边。对于原有的双向边随便定个向,连流量为1的边,意味着只能改一次方向。
    然后跑最大流,最后看是否所有与s相连的边都满流。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<queue>
    using namespace std;
    const int N=100005,inf=1e9;
    int T,n,m,h[N],cnt,le[N],in[N],out[N],s,t;
    struct qwe
    {
    	int ne,to,v;
    }e[N];
    int read()
    {
    	int r=0,f=1;
    	char p=getchar();
    	while(p>'9'||p<'0')
    	{
    		if(p=='-')
    			f=-1;
    		p=getchar();
    	}
    	while(p>='0'&&p<='9')
    	{
    		r=r*10+p-48;
    		p=getchar();
    	}
    	return r*f;
    }
    void add(int u,int v,int w)
    {
    	cnt++;
    	e[cnt].ne=h[u];
    	e[cnt].to=v;
    	e[cnt].v=w;
    	h[u]=cnt;
    }
    void ins(int u,int v,int w)
    {
    	add(u,v,w);
    	add(v,u,0);
    }
    int bfs()
    {
    	queue<int>q;
    	memset(le,0,sizeof(le));
    	le[s]=1;
    	q.push(s);
    	while(!q.empty())
    	{
    		int u=q.front();
    		q.pop();
    		for(int i=h[u];i;i=e[i].ne)
    			if(!le[e[i].to]&&e[i].v>0)
    			{
    				le[e[i].to]=le[u]+1;
    				q.push(e[i].to);
    			}
    	}
    	return le[t];
    }
    int dfs(int u,int f)
    {
    	if(!f||u==t)
    		return f;
    	int us=0;
    	for(int i=h[u];i;i=e[i].ne)
    		if(le[u]+1==le[e[i].to]&&e[i].v>0)
    		{
    			int t=dfs(e[i].to,min(e[i].v,f-us));
    			e[i].v-=t;
    			e[i^1].v+=t;
    			us+=t;
    		}
    	if(!us)
    		le[u]=0;
    	return us;
    }
    void dinic()
    {
    	int re=0;
    	while(bfs())
    		dfs(s,inf);
    }
    int main()
    {
    	T=read();
    	while(T--)
    	{
    		n=read(),m=read();
    		s=0,t=n+1;
    		cnt=1;
    		memset(h,0,sizeof(h));
    		memset(in,0,sizeof(in));
    		memset(out,0,sizeof(out));
    		for(int i=1;i<=m;i++)
    		{
    			int x=read(),y=read(),z=read();
    			out[x]++,in[y]++;
    			if(z==0)
    				ins(x,y,1);
    		}
    		bool f=1;
    		for(int i=1;i<=n;i++)
    		{
    			if((out[i]-in[i])%2==1)
    			{
    				f=0;
    				break;
    			}
    			if(out[i]-in[i]>0)
    				ins(s,i,(out[i]-in[i])/2);
    			else if(out[i]-in[i]<0)
    				ins(i,t,(in[i]-out[i])/2);
    		}
    		if(!f)
    		{
    			puts("impossible");
                continue;
            }
    		dinic();
    		for(int i=h[s];i;i=e[i].ne)
    			if(e[i].v!=0)
    			{
    				f=0;
    				break;
    			}
    		if(!f)
    			puts("impossible");
    		else
    			puts("possible");
    	}
    	return 0;
    }
    
  • 相关阅读:
    每天一点小进步(8):高效测试用例设计-XMind2TestCase
    每天一点小进步(7):Mqtt客户端理解
    每天一点小进步(6):postman使用指南
    每天一点小进步(5):python编码问题
    每天一点小进步(4): 推拉流协议初识
    每天一点小进步(3):yaml文件的相关知识点
    每天一点小进步(2):python 大文件处理
    每天一点小进步(1):lambda实现列表过滤&trim函数实现
    简单实现 随机发牌算法
    Linux学习(三)
  • 原文地址:https://www.cnblogs.com/lokiii/p/8384235.html
Copyright © 2011-2022 走看看