2017模拟赛 deep dark fantasy(网络流)

题目

题目大意:给出m条有两个可选择终点的有向边与n个点,求当满足每个点的入度与出度相同时对于每个边的选择情况

题解

考虑到入度和出度相等所以从源点向每个点连一条容量为1的边再根据加边的连接情况依次向后面的点连容量为一的点,最后在从每个点向终点连一条容量为出度的边。

代码

#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define maxn 200005
#define inf 1e9
int cnt=1;
int n,m;
int Next[maxn],End[maxn],Last[maxn],Len[maxn];
int dis[maxn],Cnt[maxn];
int chu[maxn];
int edge[maxn][3],mar[maxn];
void insert(int x,int y,int z){
    Next[++cnt]=Last[x];
    Last[x]=cnt;
    End[cnt]=y;
    Len[cnt]=z;
}
int dfs(int x,int flow){
    if(x==n+m+1) return flow;
    int i,temp,delta=0;
    for(i=Last[x];i;i=Next[i]){
        int en=End[i];
        if(dis[x]==dis[en]+1&&Len[i]>0){
            temp=dfs(en,min(Len[i],flow-delta));
            Len[i]-=temp;
            Len[i^1]+=temp;
            delta+=temp;
            if(dis[0]>=n+m+1||delta==flow) return delta;
        }
    }
    Cnt[dis[x]]--;
    if(Cnt[dis[x]]==0) dis[0]=n+m+1;
    Cnt[++dis[x]]++;
    return delta;
}
int main()
{
    int i,j,k;
    scanf("%d%d",&n,&m);
    for(i=1;i<=m;i++){
        int a,b,c;
        scanf("%d%d%d",&edge[i][0],&edge[i][1],&edge[i][2]);
        chu[edge[i][0]]++;
    }
    for(i=1;i<=m;i++){
        insert(0,i,1);
        insert(i,0,0);
    }
    int Num=0;
    for(i=1;i<=m;i++){
        insert(i,edge[i][1]+m,1);
        mar[++Num]=cnt;
        insert(edge[i][1]+m,i,0);
        insert(i,edge[i][2]+m,1);
        mar[++Num]=cnt;
        insert(edge[i][2]+m,i,0); 
    }
    for(i=1;i<=n;i++){
        if(!chu[i]) continue;
        insert(i+m,n+m+1,chu[i]);
        insert(n+m+1,i+m,0);
    }
    int temp;
    while(dis[0]<=n+m+1) temp=dfs(0,inf);
    for(i=1;i<=2*m;i+=2){
        if(Len[mar[i]]) cout<<"1";
        else cout<<"0";
    } 
}

你可能感兴趣的:(2017模拟赛 deep dark fantasy(网络流))