1. 程式人生 > >「USACO4.4」追查壞牛奶Pollutant Control 解題報告

「USACO4.4」追查壞牛奶Pollutant Control 解題報告

題面

求最小割,並且在最小割的情況下求出最少要刪去幾條邊

思路:

當然是最小割咯!

就是後一問不大好求

那怎麼辦呢? 似乎很複雜的樣子

或許我們要在模板裡改比較困難

那麼我們就想辦法在邊上做學問

比如我們可不可以把邊的容量全部加1呢?

有人問:這樣最小割不就是不一樣了嗎?

但是細想一下可以發現:其實在加1的情況下,原來的最小割確實變了,但是增大了多少就等於最少要刪去的邊數

因為對於每條邊,容量又多了一個1,在最小割的前提下,肯定是刪去越少的邊數的情況更優

舉個栗子:

強迫症,這圖畫了我半天

Code:

#include<bits/stdc++.h>
#define INF 0x7f7f7f7f
#define M 1010
#define N 50
using namespace std;
struct node{
    int to,cap;
    int nxt;
    node(int a,int b):to(a),cap(b){ }
    node(){ }
}b[M<<1];
int head[N],deep[N];
int n,m,S,T,t=1,Maxflow,Ans;
int read()
{
    int s=0;
    char c=getchar();
    while(!isdigit(c))
        c=getchar();
    while(isdigit(c))
    {
        s=(s<<1)+(s<<3)+c-'0';
        c=getchar();
    }
    return s;
}
void add(int x,int y,int cap)
{
    b[++t]=node(y,cap);
    b[t].nxt=head[x];
    head[x]=t;
    b[++t]=node(x,0);
    b[t].nxt=head[y];
    head[y]=t;
    return;
}
bool BFS()
{
    int i,cur;
    int to,cap;
    queue<int>p;
    memset(deep,0,sizeof(deep));
    deep[S]=1;p.push(S);
    while(!p.empty())
    {
        cur=p.front();p.pop();
        for(i=head[cur];i;i=b[i].nxt)
        {
            to=b[i].to;cap=b[i].cap;
            if(cap&&!deep[to])
            {
                deep[to]=deep[cur]+1;
                p.push(to);
                if(to==T)
                    return 1;
            }
        }
    }
    return 0;
}
int Dinic(int k,int flow)
{
    if(k==T)
        return flow;
    int i,to,cap,res,rest=flow;
    for(i=head[k];i&&rest;i=b[i].nxt)
    {
        to=b[i].to;cap=b[i].cap;
        if(cap&&deep[to]==deep[k]+1)
        {
            res=Dinic(to,min(rest,cap));
            if(!res)
                deep[to]=0;
            b[i].cap-=res;
            b[i^1].cap+=res;
            rest-=res;
        }
    }
    return flow-rest;
}
int main()
{
    int i,flow;
    int x,y,cap;
    n=read();m=read();
    S=1;T=n;
    for(i=1;i<=m;i++)
    {
        x=read();y=read();cap=read();
        add(x,y,cap);
    }
    while(BFS())//先求最小割
        while((flow=Dinic(S,INF)))
            Maxflow+=flow;
    while(BFS())
        while((flow=Dinic(S,INF)))
            Maxflow+=flow;
    for(i=2;i<=t;i+=2)//改變邊
        b[i].cap+=b[i^1].cap+1,b[i^1].cap=0;//初始正邊並1,反邊還是賦0
    while(BFS())//再跑一次
        while((flow=Dinic(S,INF)))
            Ans+=flow;
    printf("%d %d",Maxflow,Ans-Maxflow);//一次性輸出
    return 0;
}