hdu 5352 MZL's City 最小费用最大流

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5352

题意:M年前有一个国家发生了地震。所有城市和城市之间的路都被摧毁了。现在要重建城市。

给出一个N表示共有N个城市,M表示大地震发生在M年前,K表示每次最多只能重建K个城市。

现在从大地震发生的那年开始,每年可以进行一个操作,也就是总共有M个操作。

1 x表示可以重建和x联通(直接或间接)的城市(包括x本身),每次最多只能重建K个城市

2 x y 表示修建了一条城市x到城市y的路。

3操作给出一个p,表示有p条路被摧毁了,然后给出p个x和y表示城市x和y之间的路被摧毁了。

要求全部操作完成后最多能重建多少个城市(每个城市最多只能被重建一次)

并且要求输出每次重建城市操作的全部计划的最小字典序。

样例:

1
5 6 2
2 1 2
2 1 3
1 1
1 2
3 1 1 2
1 2表示第一年,修建了城市1和2之间的道路,第二年修建了城市1和3之间的道路。所以第三年重建城市的时候,1和2和3都是联通的。但是因为要输出最小字典序,所以第三年不选择重建。即重建了0个城市第四年1和2和3还是都联通的,选择重建城市1和城市3.即重建了2个城市第五年,城市1和城市2之间的路被摧毁。第六年,选择重建城市2,重建来1个城市。所以总共重建了3个城市 输出 0 2 1

思路:网络流。在原来的基础上增加源点s和汇点t。考虑城市,由于每个城市最多只能重建一次,所以以每个城市为点向汇点t连一条边,容量为1,费用为0.考虑1操作。由于每次最多只能重建k个城市。所以由源点s向每个1操作连一条边,容量为K。因为要最小字典序点方案。所以每次操作,先操作的费用大,后操作的费用小。可以设初始费用为M,然后后面每次-1.然后对于每个1操作。再向当前可以重建的城市连一条边,容量为1,费用为0.最后求最小费用最大流。方案就是源点向每个1操作连边的流量。
  1 #include <bits/stdc++.h>
  2 using namespace std;
  3 #define maxn 1010
  4 const int inf = 0x3f3f3f3f;
  5 struct Edge
  6 {
  7     int from, to, cap, flow, cost;
  8     Edge(int f, int t, int ca, int fl, int co)
  9     {
 10         from = f; to = t; cap = ca; flow = fl; cost = co;
 11     }
 12 };
 13 vector <Edge> edges;
 14 vector <int> G[maxn];
 15 int n, m, s, t;
 16 int d[maxn], p[maxn], a[maxn], inq[maxn];
 17 void AddEdge(int from, int to, int cap, int cost)
 18 {
 19     edges.push_back(Edge(from, to, cap, 0, cost));
 20     edges.push_back(Edge(to, from, 0, 0, -cost));
 21     m = edges.size();
 22     G[from].push_back(m-2);
 23     G[to].push_back(m-1);
 24 }
 25 bool BellmanFord(int s, int t, int &flow, int &cost)
 26 {
 27     for(int i = 0; i <= n; i++) d[i] = inf;
 28     memset(inq, 0, sizeof(inq));
 29     d[s] = 0; inq[s] = 1; p[s] = 0; a[s] = inf;
 30
 31     queue<int> q;
 32     q.push(s);
 33     while(!q.empty())
 34     {
 35         int u = q.front(); q.pop();
 36         inq[u] = 0;
 37         for(int i = 0; i < G[u].size(); i++)
 38         {
 39             Edge &e = edges[G[u][i]];
 40             if(e.cap > e.flow && d[e.to] > d[u] + e.cost)
 41             {
 42                 d[e.to] = d[u] + e.cost;
 43                 p[e.to] = G[u][i];
 44                 a[e.to] = min(a[u], e.cap - e.flow);
 45                 if(!inq[e.to])
 46                 {
 47                     q.push(e.to); inq[e.to] = 1;
 48                 }
 49             }
 50         }
 51     }
 52     if(d[t] == inf) return false;
 53     flow += a[t];
 54     cost += d[t]*a[t];
 55     int u = t;
 56     while(u!=s)
 57     {
 58         edges[p[u]].flow += a[t];
 59         edges[p[u]^1].flow -= a[t];
 60         u = edges[p[u]].from;
 61     }
 62     return true;
 63 }
 64 int flow = 0;
 65 int Mincost()
 66 {
 67     int cost = 0;
 68     while(BellmanFord(s, t, flow, cost));
 69     return cost;
 70 }
 71 int T, N, M, K;
 72 int mp[220][220];
 73 vector <int> connect;
 74 int vis[maxn];
 75 void dfs(int s)
 76 {
 77     for(int i = 1; i <= N; i++)
 78     {
 79         if(mp[s][i] == 1 && !vis[i])
 80         {
 81             connect.push_back(i);
 82             vis[i] = 1;
 83             dfs(i);
 84         }
 85     }
 86     return;
 87 }
 88 int main()
 89 {
 90     scanf("%d", &T);
 91     while(T--)
 92     {
 93         scanf("%d%d%d", &N, &M, &K);
 94         edges.clear();
 95         for(int i = 0; i <= N+M+1; i++) G[i].clear();
 96         memset(mp, 0, sizeof(mp));
 97         s = 0; t = N+M+1; n = N+M+1;
 98         for(int i = 1; i <= N; i++)
 99         {
100             mp[i][i] = 1; AddEdge(M+i, t, 1, 0);
101         }
102         int initcost = M, op, a, b, cnt = 0;
103         for(int i = 1; i <= M; i++)
104         {
105             scanf("%d", &op);
106             if(op == 1)
107             {
108                 cnt++;
109                 AddEdge(s, cnt, K, initcost);
110                 initcost--;
111                 scanf("%d", &a);
112                 connect.clear();
113                 memset(vis, 0, sizeof(vis));
114                 dfs(a);
115                 for(int j = 0; j < connect.size(); j++)
116                 {
117                     AddEdge(cnt, M+connect[j], 1, 0);
118                 }
119             }
120             else if(op == 2)
121             {
122                 scanf("%d%d", &a, &b);
123                 mp[a][b] = mp[b][a] = 1;
124             }
125             else if(op == 3)
126             {
127                 int p; scanf("%d", &p);
128                 while(p--)
129                 {
130                     scanf("%d%d", &a, &b);
131                     mp[a][b] = mp[b][a] = 0;
132                 }
133             }
134         }
135         flow = 0;
136         int cost = Mincost();
137         printf("%d\n", flow);
138         bool flag = true;
139         for(int i = 0; i < m; i += 2)
140         {
141             if(edges[i].from == s)
142             {
143                 if(flag) printf("%d", edges[i].flow), flag = false;
144                 else printf(" %d", edges[i].flow);
145             }
146         }
147         printf("\n");
148     }
149 }

hdu 5352 MZL's City 最小费用最大流

时间: 2025-01-09 00:33:53

hdu 5352 MZL's City 最小费用最大流的相关文章

HDU 5352 MZL&#39;s City(2015 多校 第5场,最小费用最大流)

  MZL's City Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 291    Accepted Submission(s): 94 Problem Description MZL is an active girl who has her own country. Her big country has N cities nu

HDU 5352 MZL&#39;s City

最小费用最大流,因为要控制字典序,网络流控制不好了...一直WA,所以用了费用流,时间早的费用大,时间晚的费用少. 构图: 建立一个超级源点和超级汇点.超级源点连向1操作,容量为K,费用为COST,然后COST-1,因为下一次遇到1操作,费用为减少1,即COST-1: 每个1操作连向当前能建造的城市,容量为1,费用为0: 每个城市连向汇点,容量为1,费用为0: #include<cstdio> #include<cstring> #include<cmath> #inc

hdu 5352 MZL&#39;s City 【二分图】

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5352 题意: 给你n,m,k 表示n个建筑 m次操作,修复操作每次最多修复k个建筑. 有三种操作 1.修复x点周围建筑(<=k) 2.x,y建筑间建边 3.x,y间删边 修复建筑时候拆点建图.反着求最大匹配,保证字典序最小. 代码: #include <stdio.h> #include <ctime> #include <math.h> #include <l

HDU 5352——MZL&#39;s City——————【二分图多重匹配、拆点】

MZL's City Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 710    Accepted Submission(s): 245 Problem Description MZL is an active girl who has her own country. Her big country has N cities numb

Hdu 5352 MZL&#39;s City (多重匹配)

题目链接: Hdu 5352 MZL's City 题目描述: 有n各节点,m个操作.刚开始的时候节点都是相互独立的,一共有三种操作: 1:把所有和x在一个连通块内的未重建过的点全部重建. 2:建立一条双向路(x,y) 3:又发生了地震,p条路被毁. 问最后最多有多少个节点被重建,输出重建节点的最小字典序. 解题思路: 这几天正好在学匹配,但是昨天下午还是没有看出来这个是匹配题目.看了题解扪心自问了自己三次,是不是傻.就是把每个需要重建的节点x拆成k个点,然后对每个拆分后的点和与拆点在同一连通块

HDU 1853 Cyclic Tour(最小费用最大流)

Cyclic Tour Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/65535 K (Java/Others) Total Submission(s): 1879    Accepted Submission(s): 938 Problem Description There are N cities in our country, and M one-way roads connecting them. Now L

hdu 4494 Teamwork 最小费用最大流

Teamwork Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=4494 Description Some locations in city A has been destroyed in the fierce battle. So the government decides to send some workers to repair these location

hdu 3488(KM算法||最小费用最大流)

Tour Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others)Total Submission(s): 2925    Accepted Submission(s): 1407 Problem Description In the kingdom of Henryy, there are N (2 <= N <= 200) cities, with M (M <= 30000

HDOJ 5352 MZL&#39;s City 匈牙利匹配

求年份和城市的匹配 MZL's City Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 539    Accepted Submission(s): 180 Problem Description MZL is an active girl who has her own country. Her big country has N