hdoj 3917 Road constructions 【最小割 之 最大权闭合图】

Road constructions

Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1475    Accepted Submission(s): 489


Problem Description
N cities are required to connect with each other by a new transportation system. After several rounds of bidding, we have selected M constructions companies and 
decided which section is assigned to which company, the associated cost and the direction of each road. 

Due to the insufficiency of national fiscal revenue and special taxation system (the tax paid by each company pays is a fixed amount and tax payment occurs at the
beginning of the construction of the project)   The government wishes to complete the project in several years and collects as much tax as possible to support the public
expense

For the restrictions of construction and engineering techniques, if a company is required to start the construction, then itself and its associated companies have to 
complete all the tasks they commit (if company A constructs a road 
from city 1 to city 2, company B constructs a road from city 2 to city 3, company C constructs a road from city 1 to city 3, we call 
companies A and B are associated and other company pairs have no such relationship, pay attention, in this example and a are not associated, in other words,’ 
associated' is a directed relationship).   
Now the question is what the maximum income the government can obtain in the first year is?
 

Input
There are multiple cases (no more than 50).
  Each test case starts with a line, which contains 2 positive integers, n and m (1<=n<=1000, 1<=m<=5000).
  The next line contains m integer which means the tax of each company.
  The Third line has an integer k  (1<=k<=3000)which indicates the number of the roads.
  Then k lines fellow, each contains 4 integers, the start of the roads, the end of the road, the company is responsible for this road and the cost of the road.
  The end of the input with two zero
 

Output
For each test case output the maximum income in a separate line, and if you can not get any income, please output 0.
 

Sample Input
      
      
4 2 500 10 4 1 2 1 10 2 3 1 20 4 3 1 30 1 4 2 60 4 2 500 100 5 1 2 1 10 2 3 1 20 4 3 1 30 4 3 2 10 1 4 2 60 3 1 10 3 1 2 1 100 2 3 1 100 3 1 1 100 0 0
 

Sample Output
      
      
440 470 0
Hint
for second test case, if you choose company 2 responsible ways, then you must choose the path of responsible company 1, but if you choose company 1, then you do not have to choose company 2.
 





题意:第一行有两个整数N和M,表示有N个城市和M个公司。政府要雇佣一些公司来修建道路使这N个城市连通。每雇佣一个公司政府可以获得税收(利润),但是修路的花销需要政府来出钱。下一行给出M个整数,表示雇佣每个公司可以获得利润。

再给出一个k,表示有k条道路。接下来k行,每行有4个整数,表示起点、终点、修路的公司、修路的花销。

如果有两个公司,A修建一个1->2的道路,B修建一条2->3的道路,那么称A和B是有依赖关系的,并且这种依赖关系是单向的,也就是说,选择了A公司就必须要选择B公司。如果选择了A公司,那么A承包的所有道路都要修建。问政府最多可以获得多少利润,若不能获取利润输出0。


少了点什么?

题目给出的k条道路保证能够连通N个城市。

我不知道是否每条道路可以由多个公司来修筑,反正我是按照每条路有且只有一个公司去修筑 来建图的。



思路:设置超级源点source,超级汇点sink

1,source向所有公司建边,容量为税收;

2,所有公司向sink建边,容量为该公司承包道路的花费之和;

3,根据依赖关系,建边容量为无穷大。

统计所有税收之和sum,最大利润就是sum - Maxlfow(source, sink)。当前若结果小于或等于0,要输出0.


AC代码


#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#define MAXN 6000
#define MAXM 50000+10
#define INF 0x3f3f3f3f
using namespace std;
struct Edge
{
    int from, to, cap, flow, next;
};
Edge edge[MAXM];
int head[MAXN], edgenum;
int dist[MAXN], cur[MAXN];
bool vis[MAXN];
int N, M;
int source, sink;//超级源点 超级汇点
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++;
}
int sum;
struct Node
{
    int from, to, company, cost;
};
Node num[MAXN];
int rec[MAXN];//记录每个公司修完所承包道路的花费
void getMap()
{
    sum = 0;
    source = 0, sink = M+1;
    int a;
    for(int i = 1; i <= M; i++)
    {
        scanf("%d", &a);
        sum += a;
        addEdge(source, i, a);//源点向该公司建边
        rec[i] = 0;
    }
    int k;
    scanf("%d", &k);
    for(int i = 0; i < k; i++)
    {
        scanf("%d%d%d%d", &num[i].from, &num[i].to, &num[i].company, &num[i].cost);
        rec[num[i].company] += num[i].cost;
    }
    for(int i = 1; i <= M; i++)//向汇点建边
        addEdge(i, sink, rec[i]);
    for(int i = 0; i < k; i++)
    {
        for(int j = 0; j < k; j++)
        {
            int u  =num[i].company;
            int v = num[j].company;
            if(i == j || u == v) continue;
            if(num[i].to == num[j].from)
                addEdge(u, v, INF);//依赖关系
        }
    }

}
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 main()
{
    while(scanf("%d%d", &N, &M), N||M)
    {
        init();
        getMap();
        int t = sum - Maxflow(source, sink);
        if(t <= 0)
            printf("0\n");
        else
            printf("%d\n", t);
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值