hdoj 3987 Harry Potter and the Forbidden Forest 【求所有最小割里面 最少的边数】

Harry Potter and the Forbidden Forest

Time Limit: 5000/3000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)

Total Submission(s): 1802    Accepted Submission(s): 602

Problem Description

Harry Potter notices some Death Eaters try to slip into Castle. The Death Eaters hide in the most depths of Forbidden Forest. Harry need stop them as soon as.

The Forbidden Forest is mysterious. It consists of N nodes numbered from 0 to N-1. All of Death Eaters stay in the node numbered 0. The position of Castle is node n-1. The nodes connected by some roads. Harry need block some roads by magic and he want to minimize
the cost. But it’s not enough, Harry want to know how many roads are blocked at least.

Input

Input consists of several test cases.

The first line is number of test case.

Each test case, the first line contains two integers n, m, which means the number of nodes and edges of the graph. Each node is numbered 0 to n-1.

Following m lines contains information about edges. Each line has four integers u, v, c, d. The first two integers mean two endpoints of the edges. The third one is cost of block the edge. The fourth one means directed (d = 0) or undirected (d = 1).

Technical Specification

1. 2 <= n <= 1000

2. 0 <= m <= 100000

3. 0 <= u, v <= n-1

4. 0 < c <= 1000000

5. 0 <= d <= 1

Output

For each test case:

Output the case number and the answer of how many roads are blocked at least.

Sample Input

3

4 5
0 1 3 0
0 2 1 0
1 2 1 1
1 3 1 1
2 3 3 1

6 7
0 1 1 0
0 2 1 0
0 3 1 0
1 4 1 0
2 4 1 0
3 5 1 0
4 5 2 0

3 6
0 1 1 0
0 1 2 0
1 1 1 1
1 2 1 0
1 2 1 0
2 1 1 1

Sample Output

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

题意:有N个点(编号从0到N-1)和M条边,边的信息有四个——起点、终点、破坏该边需要的花费、d,其中当d为1时说明边是双向的,d为0时说明是单向边。问你在花费最小的前提下,阻断0和N-1需要破坏的最少边数。

分析:

1,在原图最小割不唯一的前提下,第一次求出的最小割的边数未必是最少的。在割边集的边权和相等的前提下,可能存在一个边数更少的最小割。

2,不管有多少个最小割,我们在原图跑一次最大流之后,残量网络里面满流的边一定是属于某个或多个最小割的,相应的没有满流的边一定不属于任何一个最小割。

3,这样问题就变成——在所有满流的边中破坏最少的边数来阻断0到N-1的路径,类似在最短路的边中破坏最少的边来阻断起点到终点的路径,只是多了对非最短路边(在本题中是非满流边)的处理。

思路:

1,先建图,在原图跑一次0到N-1的最大流。

2,以残量网络为基础构建新图。遍历所有正向弧,若满流则更改边权为1,否则边权为无穷大,注意对反向弧要初始化边的信息。

3,最后在新图求一次0到N-1的最小割,就是答案。

AC代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#define MAXN 1010
#define MAXM 400000+10
#define INF 0x3f3f3f3f
using namespace std;
struct Edge
{
    int from, to, cap, flow, next;
};
Edge edge[MAXM];
int head[MAXN], cur[MAXN], edgenum;
int dist[MAXN];
bool vis[MAXN];
int N, M;
void init()
{
    edgenum = 0;
    memset(head, -1, sizeof(head));
}
void addEdge(int u, int v, int w)
{
    Edge E1 = {u, v, w, 0, head[u]};
    edge[edgenum] = E1;
    head[u] = edgenum++;
    Edge E2 = {v, u, 0, 0, head[v]};
    edge[edgenum] = E2;
    head[v] = edgenum++;
}
void getMap()
{
    int a, b, c, d;
    while(M--)
    {
        scanf("%d%d%d%d", &a, &b, &c, &d);
        a++, b++;
        addEdge(a, b, c);
        if(d)
            addEdge(b, a, c);
    }
}
bool BFS(int s, int t)
{
    queue<int> Q;
    memset(dist, -1, sizeof(dist));
    memset(vis, false, sizeof(vis));
    dist[s] = 0;
    vis[s] = true;
    Q.push(s);
    while(!Q.empty())
    {
        int u = Q.front();
        Q.pop();
        for(int i = head[u]; i != -1; i = edge[i].next)
        {
            Edge E = edge[i];
            if(!vis[E.to] && E.cap > E.flow)
            {
                dist[E.to] = dist[u] + 1;
                if(E.to == t) return true;
                vis[E.to] = true;
                Q.push(E.to);
            }
        }
    }
    return false;
}
int DFS(int x, int a, int t)
{
    if(x == t || a == 0) return a;
    int flow = 0, f;
    for(int &i = cur[x]; i != -1; i = edge[i].next)
    {
        Edge &E = edge[i];
        if(dist[E.to] == dist[x] + 1 && (f = DFS(E.to, min(a, E.cap - E.flow), t)) > 0)
        {
            edge[i].flow += f;
            edge[i^1].flow -= f;
            flow += f;
            a -= f;
            if(a == 0) break;
        }
    }
    return flow;
}
int Maxflow(int s, int t)
{
    int flow = 0;
    while(BFS(s, t))
    {
        memcpy(cur, head, sizeof(head));
        flow += DFS(s, INF, t);
    }
    return flow;
}
int k = 1;
void solve()
{
    Maxflow(1, N);
    //对残量网络 进行处理
    for(int i = 0; i < edgenum; i+=2)
    {
        Edge E = edge[i];
        if(E.cap == E.flow)//满流的边 改变边权->1
        {
            edge[i].cap = 1;
            edge[i].flow = 0;
        }
        else
        {
            edge[i].cap = INF;
            edge[i].flow = 0;
        }
        edge[i^1].cap = edge[i^1].flow = 0;//处理反向边
    }
    printf("Case %d: %d\n", k++, Maxflow(1, N));//再求一次最小割就是答案
}
int main()
{
    int t;
    scanf("%d", &t);
    while(t--)
    {
        scanf("%d%d", &N, &M);
        init();
        getMap();
        solve();
    }
    return 0;
}

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

时间: 2024-11-03 21:13:54

hdoj 3987 Harry Potter and the Forbidden Forest 【求所有最小割里面 最少的边数】的相关文章

hdu 3987 Harry Potter and the Forbidden Forest 求割边最少的最小割

view code//hdu 3987 #include <iostream> #include <cstdio> #include <algorithm> #include <cstring> #include <queue> using namespace std; typedef long long ll; const ll INF = 1LL<<59; const ll E = 100001; const int N = 10

hdu 3987 Harry Potter and the Forbidden Forest【网路流最小割模型】

Harry Potter and the Forbidden Forest Time Limit: 5000/3000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 1549    Accepted Submission(s): 528 Problem Description Harry Potter notices some Death Eaters try to slip

HDU 3987 Harry Potter and the Forbidden Forest(最小割中的最少割边)经典

Harry Potter and the Forbidden Forest Time Limit: 5000/3000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 1791    Accepted Submission(s): 596 Problem Description Harry Potter notices some Death Eaters try to slip

Harry Potter and the Forbidden Forest(割边最小的最小割)

Harry Potter and the Forbidden Forest Time Limit:3000MS    Memory Limit:65536KB    64bit IO Format:%I64d & %I64u Description Harry Potter notices some Death Eaters try to slip into Castle. The Death Eaters hide in the most depths of Forbidden Forest.

HDU3987 Harry Potter and the Forbidden Forest(边数最少的最小割)

方法1:两遍最大流.一遍最大流后,把满流边容量+1,非满流边改为INF:再求最小割即为答案. 我大概想了下证明:能构成最小割的边在第一次跑最大流时都满流,然后按那样改变边容量再求一次最小割,就相当于再在那些 满流可能是属于最小割的边 中挑出最少的边形成ST割. 1 #include<cstdio> 2 #include<cstring> 3 #include<queue> 4 #include<algorithm> 5 using namespace std

hdoj 2435 There is a war 【求原图最小割已经分成的两个点集 + 枚举两点集里面的点建新边 求残量网络的最大最小割】

There is a war Time Limit: 5000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 993    Accepted Submission(s): 283 Problem Description There is a sea. There are N islands in the sea. There are some directional

hdoj 3251 Being a Hero 【建图后求解最小割 + 输出任意一组最小割里面边 的编号】

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

hdoj 3820 Golden Eggs 【最小割+拆点】

题目:hdoj 3820 Golden Eggs 题意:给出一个矩阵,然后当前有三种选择,放一个金蛋,放一个银蛋,或者不放,然后给出每个格子放金蛋或者银蛋的得分,如果金蛋相邻的话每个得分要减掉cost1,银蛋相邻的话每个减去cost2得分,问最大得分多少? 分析:做这个题目推荐先做hdoj 1659 ,3657点击打开链接 ,这个题目相当于前两个的融合在加点变化. 首先我们发现和前两个题目一样要求不能相邻,否则要减去一定的值,那么我们可以确定同样要用当前点的行列和的奇偶性建图. 那么我们可以按照

hdoj 3657 Game 【最小割】

题目:hdoj 3657 Game 分类: 题意:给出一个矩阵,里面有值,要求按规则取一定的数使得得分最大,规则如下: 1:规定一些格子必须要拿,得分为拿了的格子的值得和 2:拿相邻的格子的需减去所有2*(x | y) 分析:这是一个标准的求最小割的题目,做这个题目推荐先做一下hdoj 1659,讲解:点击打开链接 同样是格子类题目,限制为相邻的,那么我们可以按照格子类题目的一般建图方案,按照格子的行列和的奇偶性把图分成一个二分图. 现在要求一个最大的得分,我们可以转化为求最小割来做,建图之后至