问题描述
一片海里有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);
}
}