HDU-2435-There is a war(多增加一条边,所有情况中最大的最小割)

题目

问题描述
一片海里有N个岛屿。有一些定向桥连接着这些岛屿。国家 N 可以在岛屿 2- (n-1)之间建造一座新的无敌的定向桥(只能一座桥,也可不建)。国家 1想要 最大限度地减少总破坏N的成本。国家N则需要通过做出最佳选择想要增加 1 的成本。那么最大可能的成本是多少?

输入

在这个问题上有很多种情况。
有一行是整数,告诉你开始的情况数。每种情况的第一行有两个数字,N(4<=N<=100)和M(0<=M<= N *(N -1)/2),表示岛屿的数量和桥梁的数量。下面有M行,每一行包含a, b, c三个整数,1<=a, b<=N, 1<=c<=10000,表示a到b有一个方向桥,c为破坏代价。没有两行包含相同的a和b。

输出
对于每个测试用例,都有一行带有一个整数的代码,表示可能的最大结果。
Sample Input

4
4 0
4 2
1 2 2
3 4 2
4 3
1 2 1
2 3 1
3 4 10
4 3
1 2 5
2 3 2
3 4 3

Sample Output

0
2
1
3

要学会链式前向星的删边


这里割边指 将s t两大块儿连接的边
先跑一个最小割。让一条割边以外的边变得坚固,得到的结果还是最小割。

影响1破坏N的边肯定在最小割上。或者本身不存在这个边。得到这类边的方法有两种,肯定是分成s t 两大类:

一。跑完第一遍最小割之后 !d[i] 代表与s不相连(但不一定与 t 相连) d[i]!=0代表与s相连。但是有一些根本步在网络里的点会被无辜的牵扯进来 降低了算法效率 但完全不影响答案的正确性。
既然不再网络里就不会与任何一点相连了 增加一条连接它的边也只是与一个点相连 根本没什么用的 可以提前标记一下。
二。在残余网络 dfs一遍 将可以与 s 相连的color一下,与 t 相连的color一下 连接 s t这两大块儿的边即为所求。

回归到本题上。 这个无敌的边容量设为INF 才不会被割掉

一。 重新建图 找出所有最小割最大的那一个
二。 在残余网络中跑最大流。注意跑完之后链式前向星的删边。 先将edge[i].len保存到一个数组中 用第一个方法判断割边的时候 没跑一次最大流d[i]会发生改变 也要保存到一个数组里。最小割=最大流 按最大流理解这种方法。。从最小割的角度我也没想好。。。

#include <queue>
#include <cstring>
#include <cstdio>
#define  m(a,b) memset(a,b,sizeof a)
using namespace std;
typedef long long ll;
const int N=100+5;
const int INF=0x3f3f3f3f;
struct Edge{int to,len,nex;}edge[N*(N-1)];
int head[N],d[N],tmp1[N*(N-1)],tmp2[N];
int tot,s,t,n,m;
void add(int from,int to,int len)
{
    edge[++tot]=(Edge){to,len,head[from]};head[from]=tot;
    edge[++tot]=(Edge){from,0,head[to]};head[to]=tot;
}
queue<int>q;
bool bfs()
{
    while(!q.empty())
        q.pop();
    m(d,0);
    q.push(s);
    d[s]=1;
    while(!q.empty())
    {
        int x=q.front();
        q.pop();
        for(int i=head[x];i;i=edge[i].nex)
        {
            int y=edge[i].to,l=edge[i].len;
            if(!d[y]&&l)
            {
                d[y]=d[x]+1;
                q.push(y);
                if(y==t)
                    return 1;
            }
        }
    }
    return 0;
}
int dinic(int x,int flow)
{
    if(x==t)
        return flow;
    int res=flow,k;
    for(int i=head[x];i&&res;i=edge[i].nex)
    {
        int y=edge[i].to,l=edge[i].len;
        if(l&&d[y]==d[x]+1)
        {
            k=dinic(y,(res<l)?res:l);
            if(!k)
            {
                d[y]=0;
                continue;
            }
            edge[i].len-=k;
            edge[i^1].len+=k;
            res-=k;
        }
    }
    return flow-res;
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        m(head,0);
        tot=1;
        int n,m;
        scanf("%d%d",&n,&m);
        s=1,t=n;
        while(m--)
        {
            int a,b,v;
            scanf("%d%d%d",&a,&b,&v);
            add(a,b,v);
        }
        int maxflow=0;
        while(bfs())
            maxflow+=dinic(s,INF);
        for(int i=2;i<=tot;i++)
            tmp1[i]=edge[i].len;
        for(int i=1;i<=n;i++)
            tmp2[i]=d[i];
        int maxm=0,ans;
        for(int x=2;x<n;x++)
        {
            for(int y=2;y<n;y++)
            {
                if(tmp2[x]&&!tmp2[y])
                {
                    add(x,y,INF);
                    ans=0;
                    while(bfs())
                        ans+=dinic(s,INF);
                    maxm=maxm>ans?maxm:ans;
                    head[x]=edge[tot-1].nex;
                    head[y]=edge[tot].nex;
                    tot-=2;
                    for(int i=2;i<=tot;i++)
                        edge[i].len=tmp1[i];
                }
            }
        }
        printf("%d\n",maxm+maxflow);
    }
}

猜你喜欢

转载自blog.csdn.net/qq_42576687/article/details/87856159