UVA - 10480 Sabotage (Dinic)

The regime of a small but wealthy dictatorship has been abruptly overthrown by an unexpected rebel-
lion. Because of the enormous disturbances this is causing in world economy, an imperialist military
super power has decided to invade the country and reinstall the old regime.
For this operation to be successful, communication between the capital and the largest city must
be completely cut. This is a difficult task, since all cities in the country are connected by a computer
network using the Internet Protocol, which allows messages to take any path through the network.
Because of this, the network must be completely split in two parts, with the capital in one part and
the largest city in the other, and with no connections between the parts.
There are large differences in the costs of sabotaging different connections, since some are much
more easy to get to than others.
Write a program that, given a network specification and the costs of sabotaging each connection,
determines which connections to cut in order to separate the capital and the largest city to the lowest
possible cost.
Input
Input file contains several sets of input. The description of each set is given below.
The first line of each set has two integers, separated by a space: First one the number of cities, n in
the network, which is at most 50. The second one is the total number of connections, m, at most 500.
The following m lines specify the connections. Each line has three parts separated by spaces: The
first two are the cities tied together by that connection (numbers in the range 1 − n). Then follows the
cost of cutting the connection (an integer in the range 1 to 40000000). Each pair of cites can appear
at most once in this list.
Input is terminated by a case where values of n and m are zero. This case should not be processed.
For every input set the capital is city number 1, and the largest city is number 2.
Output
For each set of input you should produce several lines of output. The description of output for each set
of input is given below:
The output for each set should be the pairs of cities (i.e. numbers) between which the connection
should be cut (in any order), each pair on one line with the numbers separated by a space. If there is
more than one solution, any one of them will do.
Print a blank line after the output for each set of input.

题意:

求图的最小割的可能方案。

思路:

暴力枚举每一条边,边的全值是否是w,判断删除之后最大流是否会减少w,如果会的话,那就真的删了它,否则还原图。

#include<iostream>
#include<algorithm>
#include<vector>
#include<stack>
#include<queue>
#include<map>
#include<set>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<ctime>

#define fuck(x) cerr<<#x<<" = "<<x<<endl;
#define debug(a, x) cerr<<#a<<"["<<x<<"] = "<<a[x]<<endl;
#define ls (t<<1)
#define rs ((t<<1)|1)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn = 100086;
const int maxm = 100086;
const int inf = 0x3f3f3f3f;
const ll Inf = 999999999999999999;
const int mod = 1000000007;
const double eps = 1e-6;
const double pi = acos(-1);

int Head[maxn],cnt;
struct edge{
    int Next,u,v;
    int w;
}e[maxm];
void add_edge(int u,int v,int w){
    e[cnt].Next=Head[u];
    e[cnt].v=v;
    e[cnt].u=u;
    e[cnt].w=w;
    Head[u]=cnt++;
}
int n,m;

int D_vis[maxn],D_num[maxn];
int source,meeting;
bool bfs()
{
    memset(D_vis,0,sizeof(D_vis));
    for(int i=0;i<=n;i++){//注意要覆盖所有点
        D_num[i]=Head[i];
    }
    D_vis[source]=1;
    queue<int>q;
    q.push(source);
    int r=0;
    while(!q.empty()){
        int u=q.front();
        q.pop();
        int k=Head[u];
        while(k!=-1){
            if(!D_vis[e[k].v]&&e[k].w){
                D_vis[e[k].v]=D_vis[u]+1;
                q.push(e[k].v);
            }
            k=e[k].Next;
        }
    }
    return D_vis[meeting];
}
int dfs(int u,int f)
{
    if(u==meeting){return f;}
    int &k=D_num[u];
    while(k!=-1){
        if(D_vis[e[k].v]==D_vis[u]+1&&e[k].w){
            int d=dfs(e[k].v,min(f,e[k].w));
            if(d>0){
                e[k].w-=d;
                e[k^1].w+=d;
                return d;
            }
        }
        k=e[k].Next;
    }
    return 0;
}
int Dinic()
{
    int ans=0;
    while(bfs()){
        int f;
        while((f=dfs(source,inf))>0){
            ans+=f;
        }
    }
    return ans;
}

int main() {
//    ios::sync_with_stdio(false);
//    freopen("in.txt", "r", stdin);
    while (scanf("%d%d",&n,&m)!=EOF&&n){
        memset(Head,-1,sizeof(Head));
        cnt=0;
        source=1;meeting=2;
        for(int i=1;i<=m;i++){
            int x,y,z;
            scanf("%d%d%d",&x,&y,&z);
            add_edge(x,y,z);
            add_edge(y,x,z);
        }

        int tot = Dinic();
        for(int j=0;j<cnt;j+=2){
            e[j].w=e[j^1].w=(e[j].w+e[j^1].w)/2;
        }

        for(int i=0;i<cnt;i+=2){
            int w = e[i].w;
            e[i].w=e[i^1].w=0;
            int tmp = Dinic();

//            fuck(tmp)
            for(int j=0;j<cnt;j+=2){
                e[j].w=e[j^1].w=(e[j].w+e[j^1].w)/2;
            }
            if(w==tot - tmp){
                printf("%d %d\n",e[i].u,e[i].v);
                tot=tmp;
            }
            else e[i].w=e[i^1].w=w;

            if(tot<=0){ break;}

        }
        printf("\n");
    }

    return 0;
}

看了网上的题解,发现了更好的方案。

求出最大流之后,图上的点已经被分为了两部分,连接两个部分的边就是一种可能的方案。

#include<iostream>
#include<algorithm>
#include<vector>
#include<stack>
#include<queue>
#include<map>
#include<set>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<ctime>

#define fuck(x) cerr<<#x<<" = "<<x<<endl;
#define debug(a, x) cerr<<#a<<"["<<x<<"] = "<<a[x]<<endl;
#define ls (t<<1)
#define rs ((t<<1)|1)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn = 100086;
const int maxm = 100086;
const int inf = 0x3f3f3f3f;
const ll Inf = 999999999999999999;
const int mod = 1000000007;
const double eps = 1e-6;
const double pi = acos(-1);

int Head[maxn],cnt;
struct edge{
    int Next,u,v;
    int w;
}e[maxm];
void add_edge(int u,int v,int w){
    e[cnt].Next=Head[u];
    e[cnt].v=v;
    e[cnt].u=u;
    e[cnt].w=w;
    Head[u]=cnt++;
}
int n,m;

int D_vis[maxn],D_num[maxn];
int source,meeting;
bool bfs()
{
    memset(D_vis,0,sizeof(D_vis));
    for(int i=0;i<=n;i++){//注意要覆盖所有点
        D_num[i]=Head[i];
    }
    D_vis[source]=1;
    queue<int>q;
    q.push(source);
    int r=0;
    while(!q.empty()){
        int u=q.front();
        q.pop();
        int k=Head[u];
        while(k!=-1){
            if(!D_vis[e[k].v]&&e[k].w){
                D_vis[e[k].v]=D_vis[u]+1;
                q.push(e[k].v);
            }
            k=e[k].Next;
        }
    }
    return D_vis[meeting];
}
int dfs(int u,int f)
{
    if(u==meeting){return f;}
    int &k=D_num[u];
    while(k!=-1){
        if(D_vis[e[k].v]==D_vis[u]+1&&e[k].w){
            int d=dfs(e[k].v,min(f,e[k].w));
            if(d>0){
                e[k].w-=d;
                e[k^1].w+=d;
                return d;
            }
        }
        k=e[k].Next;
    }
    return 0;
}
int Dinic()
{
    int ans=0;
    while(bfs()){
        int f;
        while((f=dfs(source,inf))>0){
            ans+=f;
        }
    }
    return ans;
}

int main() {
//    ios::sync_with_stdio(false);
//    freopen("in.txt", "r", stdin);
    while (scanf("%d%d",&n,&m)!=EOF&&n){
        memset(Head,-1,sizeof(Head));
        cnt=0;
        source=1;meeting=2;
        for(int i=1;i<=m;i++){
            int x,y,z;
            scanf("%d%d%d",&x,&y,&z);
            add_edge(x,y,z);
            add_edge(y,x,z);
        }
        Dinic();
        bfs();
        for(int i=1;i<=n;i++){
            D_vis[i]=min(D_vis[i],1);
        }
        for(int i=0;i<cnt;i+=2){
            if(D_vis[e[i].u]!=D_vis[e[i].v]){
                printf("%d %d\n",e[i].u,e[i].v);
            }
        }
        printf("\n");
    }
    return 0;
}

原文地址:https://www.cnblogs.com/ZGQblogs/p/11216056.html

时间: 2024-10-09 23:30:40

UVA - 10480 Sabotage (Dinic)的相关文章

UVA - 10480 Sabotage 最小割,输出割法

UVA - 10480 Sabotage 题意:现在有n个城市,m条路,现在要把整个图分成2部分,编号1,2的城市分成在一部分中,拆开每条路都需要花费,现在问达成目标的花费最少要隔开那几条路. 题解:建图直接按给你的图建一下,然后呢跑一下最大流,我们就知道了最小割是多少,答案就是最小割了  . 现在要求输出割法.我们从s开始往前跑,如果某条正向边有流量,我们就按着这条边继续往外走,知道无法再走,把所有经历过的点都染一下色.最后看所有的边,是不是有一头是染色了,另一头没有染色,如果是,这条边就是割

UVA - 10534Wavio Sequence(LIS)

题目:UVA - 10534Wavio Sequence(LIS) 题目大意:给出N个数字,找出这样的序列:2 * n + 1个数字组成.前面的n + 1个数字单调递增,后面n + 1单调递减. 解题思路:从前往后找一遍LIS,再从后往前找一遍LIS.最后只要i这个位置的LIS的长度和LDS的长度取最小值.再*2 - 1就是这个波浪数字的长度.注意这里的求LIS要用nlog(n)的算法,而且这里的波浪数字的对称并不是要求i的LIS == LDS,而是只要求LIS和LDS最短的长度就行了,长的那个

uva 725 Division(除法)暴力法!

uva 725  Division(除法) A - 暴力求解 Time Limit:3000MS     Memory Limit:0KB     64bit IO Format:%lld & %llu Description Write a program that finds and displays all pairs of 5-digit numbers that between them use the digits 0 through 9 once each, such that t

Uva 11889 - Benefit( 数论 )

Uva 11889 - Benefit( 数论 ) 题意: calculate the lowest integer B such that LCM(A, B) = C 分析: LCM(A,B) = C = A*B/GCD(A,B)C*GCD(A,B) = A*BC/A = B/GCD(A,B)如果C%A != 0 无解否则, 令t = C/AB = t * GCD(A,B) 即B 一定是 t 的整数倍从t开始枚举B #include <cstdio> typedef long long LL

UVA 10139 Factovisors(数论)

Factovisors The factorial function, n! is defined thus for n a non-negative integer: 0! = 1 n! = n * (n-1)! (n > 0) We say that a divides b if there exists an integer k such that k*a = b The input to your program consists of several lines, each conta

poj 1459 Power Network (dinic)

Power Network Time Limit: 2000MS   Memory Limit: 32768K Total Submissions: 23059   Accepted: 12072 Description A power network consists of nodes (power stations, consumers and dispatchers) connected by power transport lines. A node u may be supplied

UVA 1371 - Period(DP)

6.4 一些说明 数据属性可以重写同名的方法属性.这是为了避免在大型系统中产生问题的意外名称冲突.所以用一些减少冲突的常用方法是很有效果的.常用的方法包括:大写字母方法名称,用唯一的字符串来做为数据属性的名称(可以是个下划线_)或者用动词命名方法和用名字命名数据属性. 数据属性就像和对象的普通用户一样可以被方法引用.换句话说,类不能用来实现纯净的数据类型.事实上,在python中不能强制数据隐藏,一切基于约定.(另一方面,如C中写的,python的实现可以做到完全隐藏实现细节并且在必要是可以控制

UVa 1391 Astronauts (2SAT)

题意:给出一些宇航员他们的年龄,x是他们的平均年龄,其中A任务只能给年龄大于等于x的人,B任务只能给小于x的人,C任务没有限制.再给出m对人,他们不能同任务.现在要你输出一组符合要求的任务安排. 思路:2SAT. 设Ai表示第i个人的任务,如果i的年龄大于等于x,那么Ai=true表示分到A任务,flase表示分到C任务.如果i年龄小于x则Ai=true表示分到B任务,flase表示分到C任务. 考虑对于这m对里的每对人,如果他们是同组的,那么(Ai并非Aj)或(非Ai并Aj)等价于 (非Ai或

UVA - 111History Grading(LIS)

题目:UVA - 111History Grading(LIS) 题目大意:找最长的LIS.但是题意讲的实在是有问题. 例如:3 1 2 4 9 5 10 6 8 7,意思是第一个历史事件的时间是排在第三位,第二个历史事件是在第1位,那么首先先要将这个事件按照时间顺序重新排序.新的排列顺序:2 3 1 4 6 8 10 9 5 7. 解题思路:LIS. 代码: #include <cstdio> #include <cstring> #include <algorithm&g