题目简单来说就是让你在 2…(n−1) 之间修改一条边的权值,可以是原来存在的边,也可以是原来不存在的边,只能把权值改成INF,求最大的最小割。
这题就是稍微优化点的暴力,首先要能修改最小割,那么一定是改做完最小割之后,连接左右两块的边,之后再重新求一次最小割。
所以做完最小割之后把左右两块的点用dfs跑出来。
之后就是枚举边,我一开始是先把不存在的边也add进去,权值记为0,然后for (int i=0;i<tol;i+=2)
这样的枚举边的下标,判断如果两个点在不同块的话就修改这个边,但是貌似常数有点大,TLE了。
之后换了一种方法,枚举两个端点,并且在前面记录好他们之间的边的下标,如果不存在这个下标就给他们加边,否则就是修改原来存在的那条边,注意修改完之后要恢复。
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <queue>
using namespace std;
const int MAXN = 1000;
const int MAXM = 1e5+1000;
const int INF = 0x3f3f3f3f;
struct Edge
{
int to,cap,flow,nex;
Edge(int to,int cap,int flow,int nex):to(to),cap(cap),flow(flow),nex(nex) {}
Edge() {}
} edge[MAXM];
int head[MAXN],dis[MAXN],tol,pre[MAXM],n,m;
int vis[MAXN];
int gap[MAXN],dep[MAXN],cur[MAXN];
int mp[MAXN][MAXN];
struct node
{
int u,v,w;
} p[MAXM];
void init()
{
memset(head,-1,sizeof head);
memset(vis,0,sizeof vis);
memset(mp,0,sizeof mp);
tol=0;
}
void addedge(int u,int v,int cap)
{
edge[tol]=Edge(v,cap,0,head[u]);
head[u]=tol++;
edge[tol]=Edge(u,0,0,head[v]);
head[v]=tol++;
}
int Q[MAXN];
void BFS(int start,int end)
{
memset(dep,-1,sizeof(dep));
memset(gap,0,sizeof(gap));
gap[0] = 1;
int front = 0, rear = 0;
dep[end] = 0;
Q[rear++] = end;
while(front != rear)
{
int u = Q[front++];
for(int i = head[u]; i != -1; i = edge[i].nex)
{
int v = edge[i].to;
if(dep[v] != -1)continue;
Q[rear++] = v;
dep[v] = dep[u] + 1;
gap[dep[v]]++;
}
}
}
int S[MAXN];
int sap(int start,int end,int N)
{
BFS(start,end);
memcpy(cur,head,sizeof(head));
int top = 0;
int u = start;
int ans = 0;
while(dep[start] < N)
{
if(u == end)
{
int Min = INF;
int inser;
for(int i = 0; i < top; i++)
if(Min > edge[S[i]].cap - edge[S[i]].flow)
{
Min = edge[S[i]].cap - edge[S[i]].flow;
inser = i;
}
for(int i = 0; i < top; i++)
{
edge[S[i]].flow += Min;
edge[S[i]^1].flow -= Min;
}
ans += Min;
top = inser;
u = edge[S[top]^1].to;
continue;
}
bool flag = false;
int v;
for(int i = cur[u]; i != -1; i = edge[i].nex)
{
v = edge[i].to;
if(edge[i].cap - edge[i].flow && dep[v]+1 == dep[u])
{
flag = true;
cur[u] = i;
break;
}
}
if(flag)
{
S[top++] = cur[u];
u = v;
continue;
}
int Min = N;
for(int i = head[u]; i != -1; i = edge[i].nex)
if(edge[i].cap - edge[i].flow && dep[edge[i].to] < Min)
{
Min = dep[edge[i].to];
cur[u] = i;
}
gap[dep[u]]--;
if(!gap[dep[u]])return ans;
dep[u] = Min + 1;
gap[dep[u]]++;
if(u != start)u = edge[S[--top]^1].to;
}
return ans;
}
void dfs(int u)
{
for (int i=head[u]; ~i; i=edge[i].nex)
{
int v=edge[i].to;
if (!vis[v] && edge[i].cap > edge[i].flow)
{
vis[v] = vis[u];
dfs(v);
}
}
}
int main()
{
int t;
scanf("%d",&t);
while (t--)
{
init();
scanf("%d%d",&n,&m);
for (int i=1; i<=m; i++) scanf("%d%d%d",&p[i].u,&p[i].v,&p[i].w);
for (int k=1; k<=m; k++)
{
addedge(p[k].u,p[k].v,p[k].w);
mp[p[k].u][p[k].v]=k;
}
int ans=sap(1,n,n);
vis[1] = 1;
dfs(1);
for (int i=2;i<n;i++)
if (vis[i])
for (int j=2;j<n;j++)
{
if (i!=j)
if (!vis[j])
if (mp[i][j])
{
for (int i=0; i<tol; i++) edge[i].flow = 0;
int id=(mp[i][j]-1)*2;
int pre=edge[id].cap;
edge[id].cap = INF;
ans= max(ans,sap(1,n,n));
edge[id].cap = pre;
}
else
{
for (int i=0; i<tol; i++) edge[i].flow = 0;
addedge(i,j,INF);
ans= max(ans,sap(1,n,n));
edge[tol-2].cap = 0;
}
}
printf("%d\n",ans);
}
return 0;
}