[bzoj1143][CTSC2008]祭祀

题意:给定一个n个点m条边的有向无环图,你要选出最多的点,并且满足任意两点之间都不存在通路。2)输出每个点选了它之后还是否有最优解。   n<=100 m<=1000

题解:每个点拆两个点,把每个点向它能走到点连边,然后最小割/二分图匹配。

这题想了好久,后来想出这个模型感觉没问题.....

第二个问貌似把每个点都强行不割跑一遍应该不会T吧.....

#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#define S 0
#define T 201 
#define INF 2000000000
using namespace std;
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;
}
 
int mark[T+5];
int head[T+5],cnt=1,n,m,ans,cc=0,thead[T+5],q[T+5],top,d[T+5];
struct edge{
    int to,next,w;
}e[T*T+5];
struct tedge{
    int to,next;
}e2[1005];
 
inline void ins(int f,int t){e2[++cc]=(tedge){t,thead[f]};thead[f]=cc;}
inline void ins(int f,int t,int w)
{   
    e[++cnt]=(edge){t,head[f],w};head[f]=cnt;
    e[++cnt]=(edge){f,head[t],0};head[t]=cnt;
}
 
void build(int x,int from)
{
    if(mark[x]!=from&&x!=from) ins(from,x+n,INF),mark[x]=from;
    for(int i=thead[x];i;i=e2[i].next)
        if(mark[e2[i].to]!=from)
            build(e2[i].to,from);
}
 
int dfs(int x,int f)
{
    if(x==T)return f;
    int used=0;
    for(int i=head[x];i;i=e[i].next)
        if(e[i].w&&d[e[i].to]==d[x]+1)
        {
            int w=dfs(e[i].to,min(f-used,e[i].w));
            used+=w;e[i].w-=w;e[i^1].w+=w;
            if(used==f)return f;
        } 
    return used;
}
 
bool bfs()
{
    memset(d,0,sizeof(d));int i,j;
    for(d[q[i=top=0]=S]=1;i<=top;++i)
        for(int j=head[q[i]];j;j=e[j].next)
            if(e[j].w&&!d[e[j].to])
                d[q[++top]=e[j].to]=d[q[i]]+1;
    return d[T];
}
 
int main()
{
    ans=n=read();m=read();
    for(int i=1;i<=m;i++)
    {
        int x=read(),y=read();
        ins(y,x);
    }   
    for(int i=1;i<=n;i++)build(i,i);
    for(int i=1;i<=n;i++)ins(S,i,1),ins(i+n,T,1);
    while(bfs())ans-=dfs(S,INF);
    cout<<ans;
    return 0;
}

 

posted @ 2017-03-21 13:44  FallDream  阅读(228)  评论(0编辑  收藏  举报