HDU-3251-Being a Hero(最大权闭合子图)

题目

问题描述

国王会给你一些城市,你可以选择拥有它们 ! 你占领的城市不应该与首都相连。为了满足这个条件,你必须摧毁一些道路。同时,你必须为摧毁这些道路此付出代价 。也就是说,你的最终收入是你所占领城市的总价值,减去被毁道路的总成本。

注意,每条路都是单向的。e只有一个方向可用。有些城市是为国王保留的,所以即使首都无法到达,你也不能占领任何一座城市。首都永远是第一城市。

输入

第一行包含单个整数T (T <= 20),即测试用例的数量。每一种情况都以三个整数n、m、f (1 <= f < n <= 1000, 1 <= m < 100000)、城市数量、道路数量和可选城市数量开始。城市编号为1到n,以下m行每一行包含3个整数u, v, w,表示u市到v市的道路,费用w,以下f行每一行包含2个整数u和w,表示一个可用的u市,值w。

输出

对于每个测试用例,在第一行中打印用例号和最好的最终收益。在第二行中,打印e,即应该销毁的路的数量,然后是e个整数,即销毁的路的id。道路编号从1到m的顺序与它们在输入中出现的顺序相同。如果有多个解决方案,任何一个都可以。
Sample Input

2
4 4 2
1 2 2
1 3 3
3 2 4
2 4 1
2 3
4 4
4 4 2
1 2 2
1 3 3
3 2 1
2 4 1
2 3
4 4

Sample Output

Case 1: 3
1 4
Case 2: 4
2 1 3

最大权闭合子图模板(我也不知道是不是啦!反正都是最小割的意思 理解就好啦)。
s=1,t=n+1;…………………………ans=sum-最小割。
可以要的城市向 t 连接容量为 价格的边。两两连接的边 边容量为边的代价。
输出路径需要color一下。 。 注意找边的时候(i>>1)>m是应该break;

#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=1000+5;
const int M=100000+5;
const int INF=0x3f3f3f3f;
struct Edge{int to,len,nex;}edge[M*2+N*2];
int head[N],d[N];
bool vis[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,min(res,l));
            if(!k)
            {
                d[y]=0;
                continue;
            }
            edge[i].len-=k;
            edge[i^1].len+=k;
            res-=k;
        }
    }
    return flow-res;
}
void color(int x)
{
    vis[x]=1;
    for(int i=head[x];i;i=edge[i].nex)
    {
        int y=edge[i].to,l=edge[i].len;
        if(l&&!vis[y])
            color(y);
    }
}
int main()
{
    int T;
    scanf("%d",&T);
    for(int cas=1;cas<=T;cas++)
    {
        m(head,0);
        tot=1;
        int n,m,k;
        ll sum=0;
        scanf("%d%d%d",&n,&m,&k);
        s=1,t=n+1;
        for(int i=1;i<=m;i++)
        {
            int a,b,v;
            scanf("%d%d%d",&a,&b,&v);
            add(a,b,v);
        }
        while(k--)
        {
            int x,v;
            scanf("%d%d",&x,&v);
            sum+=v;
            add(x,t,v);
        }
        int maxflow=0;
        while(bfs())
            maxflow+=dinic(s,INF);
        m(vis,0);
        color(s);
        queue<int>Q;
        for(int i=2;i<=tot;i+=2)
        {

            if((i>>1)>m)
                break;     //剪枝。因为剩下边就是可用的城市向t连接的边了
            int x=edge[i^1].to,y=edge[i].to;
            if(vis[x]&&!vis[y])
            {
                Q.push(i>>1);
            }
        }
        printf("Case %d: %d\n",cas,sum-maxflow);
        printf("%d",Q.size());
        while(!Q.empty())
        {
            printf(" %d",Q.front());
            Q.pop();
        }
        printf("\n");
    }
}

猜你喜欢

转载自blog.csdn.net/qq_42576687/article/details/87856713
今日推荐