HDU2435 There is a war 修改一条边权值后的最小割

题目简单来说就是让你在 2(n1) 之间修改一条边的权值,可以是原来存在的边,也可以是原来不存在的边,只能把权值改成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;
}

猜你喜欢

转载自blog.csdn.net/z631681297/article/details/78232837
war