[挖坑]网络流24题

 1.飞行员配对方案问题

https://www.luogu.org/problem/show?pid=2756

二分图匹配。

#include<iostream>
#include<cstdio>
#include<queue>
#define MAXN 100
#define S 0
#define T 201
#define MAXL 10000
#define INF 200000000
using namespace std;
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;
} 

struct edge{
    int to,next,w;
}e[2*MAXL+5];
int head[T+5];
int cnt=1,n,m,ans=0;
int q[T+5];
queue<int> qu;

void ins(int f,int t,int w)
{
    e[++cnt].next=head[f];
    head[f]=cnt;
    e[cnt].to=t;
    e[cnt].w=w;
}

void insw(int f,int t,int w)
{
    ins(f,t,w);ins(t,f,0);
}

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&&q[e[i].to]==q[x]+1)
        {
            int w=dfs(e[i].to,min(e[i].w,f-used));
            used+=w;
            e[i].w-=w;
            e[i^1].w+=w;    
            if(used==f) return f;
        }    
    return used;
}

bool bfs()
{
    qu.push(S);q[S]=0;
    for(int i=1;i<=T;i++) q[i]=-1;
    while(!qu.empty())
    {
        int u=qu.front();qu.pop();
        for(int i=head[u];i;i=e[i].next)
        {
            int v=e[i].to;
            if(e[i].w&&q[v]==-1)
            {
                q[v]=q[u]+1;
                qu.push(v);    
            }    
        }    
    }
    return q[T]!=-1;
}

int main()
{
    n=read();m=read();
    int x=read(),y=read();
    while(x!=-1)
    {
        insw(x,y,1);
        x=read();y=read();    
    }
    for(int i=1;i<=n;i++) insw(S,i,1);
    for(int i=1;i<=m;i++) insw(i+n,T,1);
    while(bfs())
        ans+=dfs(S,INF);    
    printf("%d\n",ans);
    for(int i=head[S];i;i=e[i].next)
    {
        if(e[i].w) continue;int v=e[i].to;
        for(int j=head[v];j;j=e[j].next)
        {
            if(e[j].w||e[j].to==S) continue;
            printf("%d %d\n",v,e[j].to);
        }    
    }
    return 0;
}

 2.太空飞行计划问题

貌似是叫做最大权闭合图...最小割就可以了..

原题真的恶心,读入都不给数量的....换成了一道数据更大的类似的题目

http://www.lydsy.com/JudgeOnline/problem.php?id=1497

#include<iostream>
#include<cstdio>
#include<queue>
#define T 60001
#define S 0
#define MAXN 60000
#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 cnt=1,ans=0,n,m;
int head[MAXN+5];
struct edge{
    int to,next,w;
}e[5000000];
int q[MAXN+5];
queue<int> qu;

void ins(int f,int t,int w)
{
    e[++cnt].to=t;
    e[cnt].next=head[f];
    head[f]=cnt;
    e[cnt].w=w;
}

inline void insw(int f,int t,int w){ins(f,t,w);ins(t,f,0);}

bool bfs()
{
    q[S]=0;for(int i=1;i<=T;i++) q[i]=-1;
    qu.push(S);
    while(!qu.empty())
    {
        int u=qu.front();qu.pop();
        for(int i=head[u];i;i=e[i].next)
            if(e[i].w&&q[e[i].to]==-1)    
            {
                q[e[i].to]=q[u]+1;
                qu.push(e[i].to);    
            }    
    }
    return q[T]!=-1;
}

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&&q[e[i].to]==q[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;
}

int main()
{
    m=read();n=read();
    for(int i=1;i<=m;++i)
    {int c=read();insw(i+n,T,c);}
    for(int i=1;i<=n;i++)
    {
        int x=read();
        insw(i,x+n,INF);
        x=read();
        insw(i,x+n,INF);
        x=read();
        insw(S,i,x);ans+=x;
    }    
    while(bfs())
        ans-=dfs(S,INF);
    printf("%d\n",ans);
    return 0;
}

 3.最小线段覆盖问题

最大匹配

https://www.luogu.org/problem/show?pid=2764#sub

#include<iostream>
#include<cstdio>
#include<queue>
#define T 8001
#define S 0
#define MAXN 8000
#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 ne[MAXN+5];
bool yes[MAXN+5];
int cnt=1,ans=0,n,m;
int head[MAXN+5];
struct edge{
    int to,next,w;
}e[4000002];
int q[MAXN+5];
queue<int> qu;

void ins(int f,int t,int w)
{
    e[++cnt].to=t;
    e[cnt].next=head[f];
    head[f]=cnt;
    e[cnt].w=w;
}

inline void insw(int f,int t,int w){ins(f,t,w);ins(t,f,0);}

bool bfs()
{
    q[S]=0;for(int i=1;i<=T;i++) q[i]=-1;
    qu.push(S);
    while(!qu.empty())
    {
        int u=qu.front();qu.pop();
        for(int i=head[u];i;i=e[i].next)
            if(e[i].w&&q[e[i].to]==-1)    
            {
                q[e[i].to]=q[u]+1;
                qu.push(e[i].to);    
            }    
    }
    return q[T]!=-1;
}

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&&q[e[i].to]==q[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(w) 
            {
                ne[x]=e[i].to;
                if(e[i].to>n) yes[e[i].to-n]=1;
            }
            if(used==f) return f;    
        }
    }
    return used;
}

int main()
{
    n=read();m=read();int a,b;
    for(int i=1;i<=m;i++)
    {
        a=read();b=read();insw(a,b+n,1);    
    }
    for(int i=1;i<=n;i++) insw(S,i,1),insw(i+n,T,1);
    while(bfs())
        ans+=dfs(S,INF);
    for(int i=1;i<=n;i++)
    {
        if(yes[i]) continue;
        int t=i;
        while(t>0)
        {
            printf("%d ",t);
            t=ne[t]-n;
        }
        puts("");
    }
    printf("%d\n",n-ans);
    return 0;
}

4.魔术球问题

https://www.luogu.org/problem/show?pid=2765 

这道题非常巧妙...想了好久不知道怎么构图就去看了一下题解,发现和第三题一模一样.....

把两个能叠在一起的数字连边,求的就是求 使得最短路径覆盖数=输入的K 的最大数字。

第一次交最大的点跑了950+ms  好像是卡过去的。

后来想想,这道题并不需要撤销,于是就在bfs里面加了一句只往大的数字走(就是不考虑反边),只有350ms了......

 

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#define S 0
#define T 10000
#define N 5500
#define INF 200000000
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 K,cnt=1,ans;
struct edge{
    int to,next,w;
}e[150005];
int head[T+5];
int to[T+5];
queue<int> Q;
int q[T+5];
bool mark[T+5];

void INS(int f,int t,int w)
{
    e[++cnt].next=head[f];head[f]=cnt;
    e[cnt].to=t;e[cnt].w=w;
}

void ins(int f,int t,int w){INS(f,t,w);INS(t,f,0);}

int dfs(int x,int f)
{
    //cout<<"dfs"<<x<<" "<<f<<endl;
    if(x==T) return f;
    int used=0;
    for(int i=head[x];i;i=e[i].next)
    if(e[i].w&&q[e[i].to]==q[x]+1)
    {
        int w=dfs(e[i].to,min(f-used,e[i].w));
        if(w>0)
        {
            used+=w;
            e[i].w-=w;
            e[i^1].w+=w;
            mark[e[i].to-N]=1;
            to[x]=e[i].to-N;
        }
        if(used==f) return used;
    }
    if(used==0) q[x]=-1;
    return used;
}

bool bfs()
{
    for(int i=1;i<=T;i++) q[i]=-1;q[0]=0;
    Q.push(S);
    while(!Q.empty())
    {
        int u=Q.front();Q.pop();
        for(int i=head[u];i;i=e[i].next)
        if(e[i].w&&q[e[i].to]==-1&&e[i].to>u)
         {q[e[i].to]=q[u]+1;Q.push(e[i].to);}
    }
    return q[T]!=-1;
}

int main()
{
    K=read();
    int j;
    for(ans=1,j=1;;++ans,++j)
    {
        ins(S,ans,1);ins(ans+N,T,1);
        for(int i=1;i*i<2*ans;i++)
           if(i*i>ans)
               ins(ans,i*i-ans+N,1);
        while(bfs()) j-=dfs(S,INF);
        if(j>K) break;
    }
    --ans;printf("%d\n",ans);
    for(int i=1;i<=ans;i++)
    {
        if(mark[i]) continue;
        int t=i;
        while(t)
        {
            printf("%d ",t);
            t=to[t];
        }
        puts("");
    }
    return 0;
}

 5.圆桌问题http://tyvj.cn/p/1325

这道题模型非常的简单....但是没地方测啊....

好不容易发现tyvj有这道题,交上去wa光了,发现居然没有spj????????

假装已经a了

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#define S 0
#define T 501
#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;
}

queue<int> qu;
int q[505];
int n,m,ans=0,cnt=1;
int head[505];
int s[280];
struct edge{
    int to,next,w;
}e[100005];

void INS(int f,int t,int w)
{
    e[++cnt].next=head[f];head[f]=cnt;
    e[cnt].to=t;e[cnt].w=w;
}
inline void ins(int f,int t,int w){INS(f,t,w);INS(t,f,0);}

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&&q[e[i].to]==q[x]+1)
    {
        int w=dfs(e[i].to,min(e[i].w,f-used));
        e[i].w-=w;e[i^1].w+=w;
        used+=w;if(used==f) return used;
    }
    return used;
}

bool bfs()
{
    memset(q,0,sizeof(q));qu.push(S);q[S]=1;
    while(!qu.empty())
    {
        int u=qu.front();qu.pop();
        for(int i=head[u];i;i=e[i].next)
            if(e[i].w&&!q[e[i].to])
            {q[e[i].to]=q[u]+1;qu.push(e[i].to);}
    }
    return q[T]!=0;
}

int main()
{
    n=read();m=read();
    for(int i=1;i<=n;i++){s[i]=read();ans+=s[i];}
    for(int i=n;i;i--) ins(S,i,s[i]);
    for(int i=1;i<=m;i++){int x=read();ins(i+n,T,x);}
    for(int i=1;i<=n;i++)for(int j=m;j;j--)ins(i,j+n,1);
    while(bfs()) ans-=dfs(S,INF);
    if(ans) return 0*puts("0");puts("1");
    for(int i=head[S];i;i=e[i].next)
    {
        for(int j=head[e[i].to];j;j=e[j].next)
            if(!e[j].w&&e[j].to>n) printf("%d ",e[j].to-n);
        puts("");
    }
    return 0;
}

 6.餐巾计划问题/bzoj1211软件开发

题解见www.cnblogs.com/FallDream/p/liu

#include<iostream>
#include<cstdio>
#include<cstring>
#define S 0
#define T 2001
#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;
}
 
bool mark[T+5];
int head[T+5],cnt=1,n,ff,fa,fb,a,b,p=0,ans=0;
struct edge{
    int to,next,w,c;
}e[12005];
 
void ins(int f,int t,int w,int c){e[++cnt].next=head[f];head[f]=cnt;e[cnt].to=t;e[cnt].w=w;e[cnt].c=c;}
void insw(int f,int t,int w,int c){ins(f,t,w,c);ins(t,f,0,-c);}
 
int dfs(int x,int f)
{
    if(x==T) return ans+=f*p,f;
    int used=0; mark[x]=1;
    for(int i=head[x];i;i=e[i].next)
    if(!e[i].c&&e[i].w&&!mark[e[i].to])
    {
        int w=dfs(e[i].to,min(f-used,e[i].w));
        e[i].w-=w;e[i^1].w+=w;used+=w;
        if(used==f)return f;
    }
    return used;
}
 
bool modlabel()
{
    int minn=INF;
    for(int i=S;i<=T;i++)if(mark[i])
        for(int j=head[i];j;j=e[j].next) if(!mark[e[j].to]&&e[j].w)
            minn=min(minn,e[j].c);
    if(minn==INF)return false;
    for(int i=S;i<=T;i++)if(mark[i])
        for(int j=head[i];j;j=e[j].next) 
            e[j].c-=minn,e[j^1].c+=minn;
    p+=minn;
    return true;
}
 
int main()
{
    n=read();ff=read();b=read();fb=read();a=read();fa=read();
    for(int i=1;i<=n;i++)
    {   
        insw(S,i,INF,ff);int x=read();insw(S,i+n,x,0);insw(i,T,x,0);
        if(i-a>0)insw(i+n-a,i,INF,fa);
        if(i-b>0)insw(i+n-b,i,INF,fb);
    }
    for(int i=1;i<n;i++)insw(i+n,i+n+1,INF,0);
    do do memset(mark,0,sizeof(mark)); while(dfs(S,INF));while(modlabel());
    printf("%d",ans);
    return 0;
}

 7.最长递增子序列问题

https://www.luogu.org/problem/show?pid=2766

注意洛谷上的这题变成了不下降

倒着dp,求出以它为起点的最长递增序列f[i]  

每个点拆两个,一个进入,一个出去,他们之间连流量1的边

然后对于f[i]=1 从S向它连流量1的边,对于f[i]=s,从它向T连流量1  对于 i<j且a[i]<=a[j]&&f[i]==f[j]+1 从i向j连流量1的边,跑一次最大流就是答案

对于第三个问,我们把1号点和n号点之间的边、向ST连的边都改成INF就可以啦。

代码不像是我写的但是确实是我写的.....

#include<iostream>
#include<cstdio>
#include<cstring>
#define MN 2000
#define ME 1000000
#define S 0
#define T 2001
#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 f[MN + 5] , n , mx = 0 , s[MN + 5] , head[MN + 5] , cnt = 1 , q[MN + 5] , top = 0 , d[MN + 5] , ans = 0;
struct edge{int to , next , w;}e[ME + 5];

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; 
}

bool bfs()
{
    memset(d , 0 , sizeof(d));int i , j;
    for(d[q[i = top = 0] = S] = 1 ; i <= top ; i++)
        for(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] > 0;
}

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 used;
        }
    return used;
}

int main()
{
    n = read();
    for(int i = 1 ; i <= n ; i++) s[i] = read();
    for(int i = n + 1 ; i ; mx = max(mx , f[i]) , f[--i] = 1)
        for(int j = i+1 ; j <= n ; j++) 
            if(s[i] <= s[j])
                f[i] = max(f[i] , f[j] + 1);
                
    for(int i = 1 ; i <= n ; i++) ins(i , i + n , 1); 
    printf("%d\n" , mx);
    for(int i = 1 ; i <= n ; i++)
        for(int j = i + 1 ; j <= n ; j++)
            if(f[i] == f[j] + 1 && s[i] <= s[j])
                ins(i + n , j , 1);
    for(int i = 1 ; i <= n ; i++)
    {
        if(f[i] == 1)
            ins(i + n , T , 1);
        if(f[i] == mx)
            ins(S , i , 1);
    }
            
    while(bfs())ans += dfs(S , INF);
    printf("%d\n" , ans);
    
    if(mx == 1) return 0 * printf("%d" , n);
    
    cnt = 1; ans = 0;
    memset(head , 0 ,sizeof(head));
    
    for(int i = 2 ; i < n ; i++) ins(i , i + n , 1); 
    ins(1 , 1 + n , INF);ins(n , n << 1 , INF);
    for(int i = 1 ; i <= n ; i++)
        for(int j = i + 1 ; j <= n ; j++)
            if(f[i] == f[j] + 1 && s[i] <= s[j])
                ins(i + n , j , 1);
    for(int i = 1 ; i <= n ; i++)
    {
        if(f[i] == 1)
            ins(i + n , T , INF);
        if(f[i] == mx)
            ins(S , i , INF);
    }
    while(bfs())ans += dfs(S , INF);
    printf("%d\n" , ans);    
    return 0;
}

8.试题库问题

https://www.luogu.org/problem/show?pid=2763 

二分图乱匹配

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#define S 0
#define T 1021
#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 c[T+5],head[T+5],n,k,m,cnt=1,q[T+5],qx[T+5],top,s[T],d[T+5],ans=0;
struct edge{
    int to,next,w;
}e[50005];

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;
}

bool bfs()
{
    memset(d,0,sizeof(d));int i,j;
    for(d[q[i=top=0]=S]=1;i<=top;i++)
        for(int j=c[q[i]]=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 dfs(int x,int f)
{
    if(x==T)return f;
    int used=0;
    for(int&i=c[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;
}

int main()
{
    k=read();n=read();
    for(int i=1;i<=k;i++)s[i]=read();
    for(int i=k;i;i--)
    {
        ans+=s[i];
        ins(S,i+n,s[i]);
    }
    for(int i=1;i<=n;i++)
    {
        m=read();ins(i,T,1);
        for(int j=1;j<=m;j++)
            ins(read()+n,i,1);
    }
    while(bfs()) ans-=dfs(S,INF);
    if(ans) return 0*puts("No Solution!");
    for(int i=head[S];i;i=e[i].next)
    {
        printf("%d: ",e[i].to-n);
        for(int j=head[e[i].to];j;j=e[j].next)
            if(!e[j].w&&e[j].to!=S)
                printf("%d ",e[j].to);
        if(e[i].next)
        puts("");
    }
    return 0;
}

 9.方格取数问题

https://www.luogu.org/problem/show?pid=2774

#include<iostream>
#include<cstdio>
#include<cstring>
#define S 0
#define T 10001
#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 n,m,cnt=1,q[T+5],d[T+5],head[T+5],c[T+5],ans=0,top;
struct edge{
    int to,next,w;
}e[200000];

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;
}

int dfs(int x,int f)
{
    if(x==T)return f;
    int used=0;
    for(int&i=c[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=c[q[i]]=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()
{
    n=read();m=read();
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        {
            int x=read();ans+=x;
            if((i+j)&1)
                ins(S,(i-1)*m+j,x);
            else 
                ins((i-1)*m+j,T,x); 
        }
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            if((i+j)&1)
            {
                int x=(i-1)*m+j;
                if(i>1) ins(x,(i-2)*m+j,INF);
                if(j>1) ins(x,x-1,INF);
                if(i<n) ins(x,i*m+j,INF);
                if(j<m) ins(x,x+1,INF);
            } 
    while(bfs())ans-=dfs(S,INF);
    cout<<ans;
    return 0;
}

 

最小割。

10.航空计划问题

https://www.oj.swust.edu.cn/problem/show/1746

建图很好想吧..然后就是一个最大费用最大流   输出方案我都要吐血了

#include<iostream>
#include<cstdio>
#include<cstring>
#include<map>
#define S 1
#define T n<<1
#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;
}

map<string,int> mp;
string st[105],x,y;
int n,m,cnt=1,d[205],head[205],ans=0,top,tail,q[40005],p,from[5][205],mm=0,tot=1;
bool mark[205];
struct edge{
    int to,next,w,c;
}e[200000];

void ins(int f,int t,int w,int c)
{
    e[++cnt]=(edge){t,head[f],w,c};head[f]=cnt;
    e[++cnt]=(edge){f,head[t],0,-c};head[t]=cnt;
}

bool spfa()
{
      for(int i=S;i<=T;i++)d[i]=INF;
    top=tail=4000;q[top]=S;mark[S]=1;d[S]=0;
    while(top>=tail)
    {
        int u=q[tail++];
        for(int i=head[u];i;i=e[i].next)
        if(e[i].w&&d[u]+e[i].c<d[e[i].to])
        {
            d[e[i].to]=d[u]+e[i].c;from[tot][e[i].to]=i;
            if(!mark[e[i].to])
            {
                if(d[e[i].to]<d[q[tail]]) q[--tail]=e[i].to;
                else q[++top]=e[i].to; mark[e[i].to]=1;
            }        
        }    
        mark[u]=0;
    }
    return d[T]!=INF;
}

void mcf()
{
    int minn=INF;
    for(int i=from[tot][T];i;i=from[tot][e[i^1].to])
        minn=min(minn,e[i].w);
    for(int i=from[tot][T];i;i=from[tot][e[i^1].to])
    {
        ans+=e[i].c*minn;
        e[i].w-=minn;e[i^1].w+=minn;    
    }
    tot+=minn;
}

void print(int from,int to)
{
    mark[from]=1;
    for(int i=head[from];i;i=e[i].next)
        if(!mark[e[i].to]&&((!e[i].w&&e[i].c<=0)||(e[i].w&&e[i].c>=0)))
        {    
            print(e[i].to,to);
            if(e[i].to<=n) cout<<st[e[i].to]<<endl;
        }
}

int main()
{
    n=read();m=read();
    for(int i=1;i<=n;i++)
        cin>>st[i],mp[st[i]]=i;
    for(int i=1;i<=m;i++)
    {
        cin>>x>>y;int a=mp[x],b=mp[y];
        if(a>b) swap(a,b); 
        ins(a+n,b,(a==1&&b==n)?2:1,-1);
    }
    ins(1,1+n,2,0);
    for(int i=2;i<n;i++)
        ins(i,i+n,1,0);
    ins(n,T,2,0);
    while(spfa()) mcf();--tot;
    if(tot!=2) return 0*puts("No Solution!");
    cout<<-ans<<endl;top=0;
    cout<<st[1]<<endl;
    print(S,T);
    cout<<st[1]<<endl;
    return 0;
}

 11.星际转移问题

https://www.luogu.org/problem/show?pid=2754

把每个航空站都拆成天数个点,可以二分答案。

#include<iostream>
#include<cstdio>
#include<cstring>
#define S 0
#define T 15002
#define INF 2000000000
#define num(x,y) (x)*n+(y)
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 r[25],s[25][50];
int n,m,cnt=1,K,head[T+5],q[T+5],d[T+5],c[T+5],h[25],top=0;
struct edge{
    int to,next,w;
}e[T*120];

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;
    //cout<<"INS"<<f<<" "<<t<<" "<<w<<endl;
}

int dfs(int x,int f)
{
    if(x==T)return f;
    int used=0;
    for(int&i=c[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[top=i=0]=S]=1;i<=top;i++)
        for(int j=c[q[i]]=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;
    //cout<<d[T]<<endl;
    return d[T]; 
}

void build(int x)
{
    cnt=1;memset(head,0,sizeof(head));
    ins(S,n-1,K);
    for(int i=1;i<=m;i++)
        for(int j=1;j<=x;j++)
            ins(num(j-1,s[i][(j-1)%r[i]+1]),num(j,s[i][j%r[i]+1]),h[i]);
    for(int i=1;i<=x;i++)
        for(int j=1;j<=n;j++)
            ins(num(i-1,j),num(i,j),INF);
    ins(num(x,n),T,INF);
}

bool check(int x)
{
    int ans=0;
    while(bfs()) ans+=dfs(S,INF);
    //cout<<x<<" "<<ans<<endl;
    return ans==K;
} 

int main()
{
    n=read()+2;m=read();K=read();
    for(int i=1;i<=m;i++)
    {
        int x;h[i]=read();r[i]=read();
        for(int j=1;j<=r[i];j++)
            s[i][j]=(x=read())==-1?n:x==0?n-1:x;
    }
    int l=1,r=1000,ans=0,mid;
    while(l<=r)
    {
        mid=l+r>>1;build(mid);
        if(check(mid)) ans=mid,r=mid-1;
        else l=mid+1;
    }
    cout<<ans;
    return 0;
}

 

posted @ 2017-02-24 15:11  FallDream  阅读(282)  评论(0编辑  收藏  举报