Being a Hero HDU - 3251 (最小割)

16 篇文章 0 订阅
6 篇文章 0 订阅

You are the hero who saved your country. As promised, the king will give you some cities of the country, and you can choose which ones to own!

But don’t get too excited. The cities you take should NOT be reachable from the capital – the king does not want to accidentally enter your area. In order to satisfy this condition, you have to destroy some roads. What’s worse, you have to pay for that – each road is associated with some positive cost. That is, your final income is the total value of the cities you take, minus the total cost of destroyed roads.

Note that each road is a unidirectional, i.e only one direction is available. Some cities are reserved for the king, so you cannot take any of them even if they’re unreachable from the capital. The capital city is always the city number 1.
Input
The first line contains a single integer T (T <= 20), the number of test cases. Each case begins with three integers n, m, f (1 <= f < n <= 1000, 1 <= m < 100000), the number of cities, number of roads, and number of cities that you can take. Cities are numbered 1 to n. Each of the following m lines contains three integers u, v, w, denoting a road from city u to city v, with cost w. Each of the following f lines contains two integers u and w, denoting an available city u, with value w.
Output
For each test case, print the case number and the best final income in the first line. In the second line, print e, the number of roads you should destroy, followed by e integers, the IDs of the destroyed roads. Roads are numbered 1 to m in the same order they appear in the input. If there are more than one solution, any one will do.
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
按要求建图就好,边的容量就是摧毁道路所需要的花费,另外所有可选的城市和一个超级汇点连边,权值为城市的价值,然后从1到超级汇点跑最大流,答案就是总城市价值减去最大流。
该这样去理解,我们要做的就是使得我们要选的点和1无法到达,最小割就是做这样的事情假设割掉的边在路上,那么相对选了城市之后,我是不亏的,起码小赚,但是如果割掉的是我们选的城市到汇点是什么含义呢,就是说我们不选这个点了嘛~~~

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<queue>
#define INF 0x3f3f3f3f
#define N 100005
using namespace std;
const int maxn=1005;
const int maxx=220000;
int edge;
int to[maxx],flow[maxx],nex[maxx];
int head[maxn];

void addEdge(int v,int u,int cap)
{
    to[edge]=u,flow[edge]=cap,nex[edge]=head[v],head[v]=edge++;
    to[edge]=v,flow[edge]=0,nex[edge]=head[u],head[u]=edge++;
}
int vis[maxn];
int pre[maxn];
bool bfs(int s,int e)
{
    queue<int> que;
    pre[s]=-1;
    memset(vis,-1,sizeof(vis));
    que.push(s);
    vis[s]=0;
    while(!que.empty())
    {
        int u=que.front();
        que.pop();
        for(int i=head[u];~i;i=nex[i])
        {
            int v=to[i];
            if(vis[v]==-1&&flow[i])
            {
                vis[v]=vis[u]+1;
                if(v==e)
                    return true;
                que.push(v);
            }

        }
    }
    return false;
}
int dfs(int s,int t,int f)
{
    if(s==t||!f)
        return f;
    int r=0;
    for(int i=head[s];~i;i=nex[i])
    {
        int v=to[i];
        if(vis[v]==vis[s]+1&&flow[i])
        {
            int d=dfs(v,t,min(f,flow[i]));
            if(d>0)
            {
                flow[i]-=d;
                flow[i^1]+=d;
                r+=d;
                f-=d;
                if(!f)
                    break;
            }
        }
    }
    if(!r)
        vis[s]=INF;
    return r;
}
int maxFlow(int s ,int e)//然后直接调用这个即可
{
    int ans=0;
    while(bfs(s,e))
        ans+=dfs(s,e,INF);
    return ans;
}
void dfs(int u)
{
    vis[u]=1;
    for(int i=head[u];~i;i=nex[i])
    {
        int v=to[i];
        if(vis[v]||!flow[i])
            continue;
        dfs(v);
    }
}
void init()//记得每次使用前初始化
{
    memset(head,-1,sizeof(head));
    edge=0;
}
int ans[100005];
int main()
{
    int t;
    int x,y,w;
    int n,m,f;
    scanf("%d",&t);
    int cal=1;
    while(t--)
    {
        scanf("%d%d%d",&n,&m,&f);
        init();
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d%d",&x,&y,&w);
            addEdge(x,y,w);
        }
        int total=0;
        while(f--)
        {
            scanf("%d%d",&x,&w);
            addEdge(x,n+1,w);
            total+=w;
        }
        printf("Case %d: %d\n",cal++,total-maxFlow(1,n+1));
        memset(vis,0,sizeof(vis));
        dfs(1);
        int cnt=0;
        for(int i=0;i<edge;i+=2)
        {
            int u=to[i^1],v=to[i];
            if(vis[u]&&!vis[v])
            {
                int temp=i/2+1;
                if(temp<=m)
                    ans[cnt++]=temp;
            }
        }
        printf("%d",cnt);
        for(int i=0;i<cnt;i++)
            printf(" %d",ans[i]);
        printf("\n");
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值