There is a war (hdu 2435 最小割+枚举)

There is a war

Time Limit: 5000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)

Total Submission(s): 970    Accepted Submission(s): 277

Problem Description

There is a sea.

There are N islands in the sea.

There are some directional bridges connecting these islands.

There is a country called Country One located in Island 1.

There is another country called Country Another located in Island N.

There is a war against Country Another, which launched by Country One.

There is a strategy which can help Country Another to defend this war by destroying the bridges for the purpose of making Island 1 and Island n disconnected.

There are some different destroying costs of the bridges.

There is a prophet in Country Another who is clever enough to find the minimum total destroying costs to achieve the strategy.

There is an architecture in Country One who is capable enough to rebuild a bridge to make it unbeatable or build a new invincible directional bridge between any two countries from the subset of island 2 to island n-1.

There is not enough time for Country One, so it can only build one new bridge, or rebuild one existing bridge before the Country Another starts destroying, or do nothing if happy.

There is a problem: Country One wants to maximize the minimum total destroying costs Country Another needed to achieve the strategy by making the best choice. Then what’s the maximum possible result?

Input

There are multiple cases in this problem.

There is a line with an integer telling you the number of cases at the beginning.

The are two numbers in the first line of every case, N(4<=N<=100) and M(0<=M<=n*(n-1)/2), indicating the number of islands and the number of bridges.

There are M lines following, each one of which contains three integers a, b and c, with 1<=a, b<=N and 1<=c<=10000, meaning that there is a directional bridge from a to b with c being the destroying cost.

There are no two lines containing the same a and b.

Output

There is one line with one integer for each test case, telling the maximun possible result.

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

Source

2008 Asia Chengdu Regional Contest Online

Recommend

lcy   |   We have carefully selected several similar problems for you:  2433 2432 2430 2429 2431

题意:n个国家,m条有向边,国家1要去攻打国家n,n想切断1到n的道路来防御,切断每条道路有一定费用,国家1有一个NB魔法,可以建一条新边或者加固一条已有的边,这条边不能被n破坏,现在求 最大化n国花费之和的最小值。

思路:可知就是求最小割边集,先建图,跑一遍最大流得ans,然后从S集到T集枚举割边使容量为INF,在残留网络中再跑网络流并记录最大值Max,那么最后答案就是ans+Max。在枚举的时候也可以直接重新建图,这样应该好理解一些。

代码:

#include <iostream>
#include <functional>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <string>
#include <map>
#include <stack>
#include <vector>
#include <set>
#include <queue>
#pragma comment (linker,"/STACK:102400000,102400000")
#define pi acos(-1.0)
#define eps 1e-6
#define lson rt<<1,l,mid
#define rson rt<<1|1,mid+1,r
#define FRE(i,a,b)  for(i = a; i <= b; i++)
#define FREE(i,a,b) for(i = a; i >= b; i--)
#define FRL(i,a,b)  for(i = a; i < b; i++)
#define FRLL(i,a,b) for(i = a; i > b; i--)
#define mem(t, v)   memset ((t) , v, sizeof(t))
#define sf(n)       scanf("%d", &n)
#define sff(a,b)    scanf("%d %d", &a, &b)
#define sfff(a,b,c) scanf("%d %d %d", &a, &b, &c)
#define pf          printf
#define DBG         pf("Hi\n")
typedef long long ll;
using namespace std;

#define INF 0x3f3f3f3f
#define mod 1000000009
const int maxn = 1005;
const int MAXN = 2005;
const int MAXM = 200010;

struct Edge
{
    int to,next,cap,flow;
}edge[MAXM],e[MAXM];

int n,m;
int tol;
int head[MAXN];
int gap[MAXN],dep[MAXN],pre[MAXN],cur[MAXN],hed[MAXN];
int S[MAXN],T[MAXN];

void init()
{
    tol=0;
    memset(head,-1,sizeof(head));
}

//加边,单向图三个参数,双向图四个参数
void addedge(int u,int v,int w,int rw=0)
{
    edge[tol].to=v; edge[tol].cap=w; edge[tol].next=head[u];
    edge[tol].flow=0; head[u]=tol++;
    edge[tol].to=u; edge[tol].cap=rw; edge[tol].next=head[v];
    edge[tol].flow=0; head[v]=tol++;
}

//输入参数:起点,终点,点的总数
//点的编号没有影响,只要输入点的总数
int sap(int start,int end,int N)
{
    memset(gap,0,sizeof(gap));
    memset(dep,0,sizeof(dep));
    memcpy(cur,head,sizeof(head));
    int u=start;
    pre[u]=-1;
    gap[0]=N;
    int ans=0;
    while (dep[start]<N)
    {
        if (u==end)
        {
            int Min=INF;
            for (int i=pre[u];i!=-1;i=pre[edge[i^1].to])
                if (Min>edge[i].cap-edge[i].flow)
                    Min=edge[i].cap-edge[i].flow;
            for (int i=pre[u];i!=-1;i=pre[edge[i^1].to])
            {
                edge[i].flow+=Min;
                edge[i^1].flow-=Min;
            }
            u=start;
            ans+=Min;
            continue;
        }
        bool flag=false;
        int v;
        for (int i=cur[u];i!=-1;i=edge[i].next)
        {
            v=edge[i].to;
            if (edge[i].cap-edge[i].flow && dep[v]+1==dep[u])
            {
                flag=true;
                cur[u]=pre[v]=i;
                break;
            }
        }
        if (flag)
        {
            u=v;
            continue;
        }
        int Min=N;
        for (int i=head[u];i!=-1;i=edge[i].next)
            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[pre[u]^1].to;
    }
    return ans;
}

bool vis[MAXN];

void dfs(int u)
{
    vis[u]=true;
    for (int i=head[u];~i;i=edge[i].next)
    {
        int v=edge[i].to;
        if (edge[i].cap-edge[i].flow>0&&!vis[v])
            dfs(v);
    }
}

int main()
{
#ifndef ONLINE_JUDGE
    freopen("C:/Users/lyf/Desktop/IN.txt","r",stdin);
#endif
    int i,j,t,u,v,w;
    scanf("%d",&t);
    while (t--)
    {
        scanf("%d%d",&n,&m);
        init();
        for (i=0;i<m;i++)
        {
            scanf("%d%d%d",&u,&v,&w);
            addedge(u,v,w);
        }
        int ans=sap(1,n,n);
        memset(vis,false,sizeof(vis));
        dfs(1);
        int ss=0,tt=0;
        for (i=1;i<=n;i++)
        {
            if (vis[i]) S[ss++]=i;
            else T[tt++]=i;
        }
//        printf("%d %d\n",ss,tt);
        for (i=0;i<tol;i++)
            e[i]=edge[i];
        for (i=1;i<=n;i++)
            hed[i]=head[i];
        int Max=0;
        for (i=0;i<ss;i++)
        {
            for (j=0;j<tt;j++)
            {
                for (int k=0;k<tol;k++)
                    edge[k]=e[k];
                for (int k=1;k<=n;k++)
                    head[k]=hed[k];
                if (S[i]==1||T[j]==n) continue;
                addedge(S[i],T[j],INF);
                int x=sap(1,n,n);
                Max=max(Max,x);
                tol-=2;
            }
        }
        printf("%d\n",ans+Max);
    }
    return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-11 04:15:17

There is a war (hdu 2435 最小割+枚举)的相关文章

HDU 2435 There is a war (网络流-最小割)

There is a war Problem Description There is a sea. There are N islands in the sea. There are some directional bridges connecting these islands. There is a country called Country One located in Island 1. There is another country called Country Another

hdu 3657 最小割的活用 / 奇偶方格取数类经典题 /最小割

题意:方格取数,如果取了相邻的数,那么要付出一定代价.(代价为2*(X&Y))(开始用费用流,敲升级版3820,跪...) 建图:  对于相邻问题,经典方法:奇偶建立二分图.对于相邻两点连边2*(X&Y),源->X连边,Y->汇连边,权值w为点权. ans=总点权-最小割:如果割边是源->X,表示x不要选(是割边,必然价值在路径上最小),若割边是Y-汇点,同理:若割边是X->Y,则表示选Y点且选X点, 割为w( 2*(X&Y) ). 自己的确还没有理解其本质

hdu 3204(最小割--关键割边)

Ikki's Story I - Road Reconstruction Time Limit: 2000MS   Memory Limit: 131072K Total Submissions: 7491   Accepted: 2172 Description Ikki is the king of a small country – Phoenix, Phoenix is so small that there is only one city that is responsible fo

hdu 5076 最小割灵活的运用

题意比较复杂,其实关键是抽象出来:每个点,可以赋予俩个值(二选一,必需选一个,设ai,bi).  求所有之和最大,有条件:若俩个点同时满足: 1,:点的二进制只有一位不同.  2:至少有一个是选B值: 则可获得对应加成. 这题开始想了半天,建图遇到问题,看了官方说是最小割,于是入手: a值就是小于阈值的最大值,B值就是大于等于的最大值. 思路:俩个点选其一,必然想到建二分(每个点一分为二)图,中间连无穷的边.因为只有一位不同,必然分奇偶点,有奇数个1的点,源点到他为A值,对应点到汇点为B值,偶点

hdu 1565 最小割

黑白染色,源指向白,黑指向汇,容量都是方格中数的大小,相邻的格子白指向黑,容量为oo,然后求一次最小割. 这个割是一个简单割,如果只选择不在割中的点,那么一种割就和一个选数方案一一对应,割的大小就是不选的那些数的大小,我们需要最小化这个值. 答案=总和-最小割 1 #include <cstdio> 2 #include <cstring> 3 #include <queue> 4 #include <vector> 5 #define maxn 410 6

Being a Hero (hdu 3251 最小割 好题)

Being a Hero Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 1211    Accepted Submission(s): 381 Special Judge Problem Description You are the hero who saved your country. As promised, the ki

HDU 3526 最小割

点击打开链接 题意:有两个公司分别提供的n个部件,每个部件的价格给出,现在要这买n个部件,我可以选择两个公司中的任意一个,但是对于下面给的m个关系来说,若满足i与j不再同一个公司,那么就要加上c的费用,问买n个部件的最小花费 思路:刚刚读完题的时候感觉像是最小费用流呐,流量就是5呗,然后根据关系建图,画了一会也画不出来,看了一下正解竟然是最小割,思想到时很简单,但是思路不对的话还是很难想到的,建图就是源点,中间一列n个部件,然后汇点,源点连中间的话就是A公司的n个物品,然后中间连汇点的话就是B公

hdu 1569 最小割

和HDU 1565是一道题,只是数据加强了,貌似轮廓线DP来不了了. 1 #include <cstdio> 2 #include <cstring> 3 #include <queue> 4 #include <vector> 5 #define maxn 2510 6 #define oo 0x3f3f3f3f 7 using namespace std; 8 9 struct Edge { 10 int u, v, f; 11 Edge( int u,

hdu 3046 最小割

每个栅栏其实就是一条边,修一些栅栏,使得狼不能抓到羊,其实就是求一个割,使得羊全在S中,狼全在T中. 1 #include <cstdio> 2 #include <cstring> 3 #include <vector> 4 #include <queue> 5 #define maxn 40010 6 #define oo 0x3f3f3f3f 7 #define clr(arr,n) memset(&arr,0,sizeof(arr[0])*(