HDU 3488--Tour(KM or 费用流)
因为每个点只能经过一次 所以考虑拆点
这题有坑,有重边。。
KM算法
把一个点拆成入点和出点 入点在X部,出点在Y步。
如果u,v之间有路径,就在X部的u点连接Y部的v点
求完美匹配。
当完美匹配的时候,每个点都有一个入度和一个出度,可知成环。
因为完美匹配求得是最大匹配
记得把每条边权值取相反数
#include <iostream>
#include <cstring>
#include <cstdio> using namespace std;
const int MAXN = ;
const int INF = 0x3f3f3f3f; int G[MAXN][MAXN];
int vx[MAXN], vy[MAXN];
bool visx[MAXN], visy[MAXN];
int match[MAXN];
int slack[MAXN]; int N, M; bool dfs(int x)
{
visx[x] = true; for (int y = ; y < N; ++y) { if (visy[y]) continue; int gap = vx[x] + vy[y] - G[x][y]; if (gap == ) {
visy[y] = true;
if (match[y] == - || dfs( match[y] )) {
match[y] = x;
return true;
}
} else {
slack[y] = min(slack[y], gap);
}
} return false;
} int KM()
{
memset(match, -, sizeof match);
memset(vy, , sizeof vy); for (int i = ; i < N; ++i) {
vx[i] = G[i][];
for (int j = ; j < N; ++j) {
vx[i] = max(vx[i], G[i][j]);
}
} for (int i = ; i < N; ++i) { fill(slack, slack + N, INF); while () {
memset(visx, false, sizeof visx);
memset(visy, false, sizeof visy); if (dfs(i)) break; int d = INF;
for (int j = ; j < N; ++j)
if (!visy[j]) d = min(d, slack[j]); for (int j = ; j < N; ++j) {
if (visx[j]) vx[j] -= d;
if (visy[j]) vy[j] += d;
else slack[j] -= d;
}
}
} int res = ;
for (int i = ; i < N; ++i)
res += G[ match[i] ][i]; return res;
} int Scan() {
int res = , flag = ;
char ch;
if((ch = getchar()) == '-') flag = ;
else if(ch >= '' && ch <= '') res = ch - '';
while((ch = getchar()) >= '' && ch <= '')
res = res * + (ch - '');
return flag ? -res : res;
} int main()
{
int T = Scan();
while (T--) {
N = Scan(), M = Scan();
for (int i = ; i <= N; ++i) {
for (int j = ; j <= N; ++j) {
G[i][j] = -INF;
}
}
int u, v, w;
while (M--) {
u = Scan()-, v = Scan()-, w = Scan();
G[u][v] = max(G[u][v], -w);
} printf("%d\n", -KM());
}
return ;
}
费用流
就是把上面的完美匹配用网络流来求。。
和完美匹配一样
如果u,v之间有路径,就u的入点连v的出点,然后所有入点连起点,所有出点连汇点,求最大流最小花费即可。
费用流比起KM慢了几倍。。
#include <algorithm>
#include <iostream>
#include <cstring>
#include <string>
#include <vector>
#include <bitset>
#include <cstdio>
#include <queue>
#include <stack>
#include <cmath>
#include <list>
#include <map>
#include <set>
#define pk(x) printf("%d\n", x)
using namespace std;
#define PI acos(-1.0)
#define EPS 1E-6
#define clr(x,c) memset(x,c,sizeof(x))
//#pragma comment(linker, "/STACK:102400000,102400000") typedef long long ll;
#define CLR(x, v, n) memset(x, v, sizeof(x[0])*n)
const int N = ;
const int M = ;
const int INF = 0x3f3f3f3f; struct Edge {
int to, next, cap, flow, cost;
void init(int _to, int _cap, int _cost, int _next) {
to = _to; cap = _cap; cost = _cost; next = _next; flow = ;
}
} edge[M]; int head[N], cntE;
int pre[N], dis[N];
bool vis[N];
int src, sink, tot; void dn(int &x, int y) { if(x>y) x=y; } void init() {
cntE = ;
memset(head, -, sizeof head);
} void addedge(int u, int v, int cap, int cost) {
edge[cntE].init(v, cap, cost, head[u]); head[u] = cntE++;
edge[cntE].init(u, , -cost, head[v]); head[v] = cntE++;
} bool spfa() {
queue<int> q;
fill(dis, dis+tot, INF); CLR(vis, false, tot); CLR(pre, -, tot);
dis[src] = ; vis[src] = true;
q.push(src);
while (q.size()) {
int u = q.front(); q.pop(); vis[u] = false;
for (int i = head[u]; ~i; i = edge[i].next) {
int v = edge[i].to;
if (edge[i].cap > edge[i].flow && dis[u]+edge[i].cost < dis[v]) {
dis[v] = dis[u]+edge[i].cost;
pre[v] = i;
if (!vis[v]) {
vis[v] = true;
q.push(v);
}
}
}
}
if (pre[sink] == -) return false;
return true;
} int MCMF() {
int flow = ;
int cost = ;
while (spfa()) {
int f = INF;
for (int i = pre[sink]; ~i; i = pre[edge[i^].to]) {
dn(f, edge[i].cap - edge[i].flow);
}
for (int i = pre[sink]; ~i; i = pre[edge[i^].to]) {
edge[i].flow += f;
edge[i^].flow -= f;
cost += edge[i].cost * f;
}
flow += f;
}
//return flow;
return cost;
} int Scan() {
int res = , flag = ;
char ch;
if((ch = getchar()) == '-') flag = ;
else if(ch >= '' && ch <= '') res = ch - '';
while((ch = getchar()) >= '' && ch <= '')
res = res * + (ch - '');
return flag ? -res : res;
} int n, m;
int G[][];
int main()
{
int T = Scan();
while (T--) {
clr(head, -);
cntE = ;
n = Scan(), m = Scan();
int u, v, w;
src = , sink = n*+, tot = n*+;;
for (int i = ; i <= n; ++i) {
addedge(src, i, , );
addedge(i+n, sink, , );
}
for (int i = ; i <= n; ++i) for (int j = ; j <= n; ++j) G[i][j] = INF;
while (m--) {
u = Scan(), v = Scan(), w = Scan();
G[u][v] = min(G[u][v], w);
}
for (int i = ; i <= n; ++i) for (int j = ; j <= n; ++j) {
if (G[i][j] != INF) {
addedge(i, j+n, , G[i][j]);
}
}
printf("%d\n", MCMF());
}
return ;
}
上面的费用流太慢辣,又找了个快点的。嘿嘿XD
#include <algorithm>
#include <iostream>
#include <cstring>
#include <string>
#include <vector>
#include <bitset>
#include <cstdio>
#include <queue>
#include <stack>
#include <cmath>
#include <list>
#include <map>
#include <set>
#define pk(x) printf("%d\n", x)
using namespace std;
#define PI acos(-1.0)
#define EPS 1E-6
#define clr(x,c) memset(x,c,sizeof(x))
//#pragma comment(linker, "/STACK:102400000,102400000") typedef long long ll; const int MAXV = ;
const int INF = <<; struct Edge { int to, cap, cost, rev; };
vector<Edge> G[MAXV];
int dist[MAXV], prv[MAXV], pre[MAXV], in[MAXV];
queue<int> que; void addedge(int from, int to, int cap, int cost) {
G[from].push_back((Edge){to, cap, cost, G[to].size()});
G[to].push_back((Edge){from, , -cost, G[from].size()-});
} int min_cost_max_flow(int s, int t) { //, int f) {
int res = ;
int f = ;
while () { //f > 0) {
for (int i = ; i <= t; ++i) dist[i] = INF, in[i] = ;
dist[s] = ;
while (!que.empty()) que.pop();
in[s] = ;
que.push(s); while (!que.empty()) {
int u = que.front(); que.pop(); in[u] = ;
for (int i = ; i < G[u].size(); ++i) {
Edge &e = G[u][i];
if (e.cap > && dist[e.to] > dist[u] + e.cost) {
dist[e.to] = dist[u] + e.cost;
prv[e.to] = u;
pre[e.to] = i;
if (in[e.to] == ) {
in[e.to] = ;
que.push(e.to);
}
}
}
} if (dist[t] == INF) break; //return -1; int d = INF; // d = f;
for (int v = t; v != s; v = prv[v]) {
d = min(d, G[prv[v]][pre[v]].cap);
}
f += d;
res += d * dist[t];
for (int v = t; v != s; v = prv[v]) {
Edge &e = G[prv[v]][pre[v]];
e.cap -= d;
G[v][e.rev].cap += d;
}
}
return res;
} int Scan() {
int res = , flag = ;
char ch;
if((ch = getchar()) == '-') flag = ;
else if(ch >= '' && ch <= '') res = ch - '';
while((ch = getchar()) >= '' && ch <= '')
res = res * + (ch - '');
return flag ? -res : res;
} int n, m;
int mp[][];
int main()
{
int T = Scan();
while (T--) {
n = Scan(), m = Scan();
int u, v, w;
int src = , sink = n*+;
for (int i = ; i <= sink; ++i) G[i].clear();
for (int i = ; i <= n; ++i) {
addedge(src, i, , );
addedge(i+n, sink, , );
}
for (int i = ; i <= n; ++i) for (int j = ; j <= n; ++j) mp[i][j] = INF;
while (m--) {
u = Scan(), v = Scan(), w = Scan();
mp[u][v] = min(mp[u][v], w);
}
for (int i = ; i <= n; ++i) for (int j = ; j <= n; ++j) {
if (mp[i][j] != INF) {
addedge(i, j+n, , mp[i][j]);
}
}
printf("%d\n", min_cost_max_flow(src, sink));
}
return ;
}
HDU 3488--Tour(KM or 费用流)的更多相关文章
- Hdu 3488 Tour (KM 有向环覆盖)
题目链接: Hdu 3488 Tour 题目描述: 有n个节点,m条有权单向路,要求用一个或者多个环覆盖所有的节点.每个节点只能出现在一个环中,每个环中至少有两个节点.问最小边权花费为多少? 解题思路 ...
- hdoj 3488 Tour 【最小费用最大流】【KM算法】
Tour Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 65535/65535 K (Java/Others) Total Submi ...
- hdu 1533 KM或费用流
以前用KM写过,现在再用费用流写. #include <iostream> #include <cstdio> #include <cstring> #includ ...
- 【进阶——最小费用最大流】hdu 1533 Going Home (费用流)Pacific Northwest 2004
题意: 给一个n*m的矩阵,其中由k个人和k个房子,给每个人匹配一个不同的房子,要求所有人走过的曼哈顿距离之和最短. 输入: 多组输入数据. 每组输入数据第一行是两个整型n, m,表示矩阵的长和宽. ...
- HDU 5644 King's Pilots 费用流
King's Pilots 题目连接: http://acm.hdu.edu.cn/showproblem.php?pid=5644 Description The military parade w ...
- HDU 3667 Transportation(网络流之费用流)
题目地址:HDU 3667 这题的建图真是巧妙...为了保证流量正好达到k.须要让每一次增广到的流量都是1,这就须要把每一条边的流量都是1才行.可是每条边的流量并非1,该怎么办呢.这个时候能够拆边,反 ...
- HDU - 5406 CRB and Apple (费用流)
题意:对于给定的物品,求两个在高度上单调不递增,权值上单调不递减的序列,使二者长度之和最大. 分析:可以用费用流求解,因为要求长度和最大,视作从源点出发的流量为2的费用流,建负权边,每个物品只能取一次 ...
- 图论(二分图,KM算法):HDU 3488 Tour
Tour Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 65535/65535 K (Java/Others)Total Submis ...
- HDU 3488 Tour (最大权完美匹配)【KM算法】
<题目链接> 题目大意:给出n个点m条单向边边以及经过每条边的费用,让你求出走过一个哈密顿环(除起点外,每个点只能走一次)的最小费用.题目保证至少存在一个环满足条件. 解题分析: 因为要求 ...
随机推荐
- source code analyzer 功能强大的C/C++源代码分析软件 Celerity CRACK 破解版
特色 迅捷是一个功能强大的C/C++源代码分析软件.可以处理数百万行的源程序代码.支持标准及K&R风格的C/C++.对每一个打开的源代码工程,通过建立一个包含丰富交叉引用关系的数据库,显示其所 ...
- 在NEXUS中加入自己定义的第三方PROXIES代理库
就是要等会耐心,更新好之后,才能在PUBLIC库里进行操作. 下图是JBOSS的
- 【转】Java自动装箱、拆箱、缓冲池
JDK5以后 Integer a = 3; 这是自动装箱int i = new Integer(2); 这是自动拆箱就是基本类型和其对应的包装类型在需要的时候可以互相 ...
- eclipse连接远程Hadoop报错,Caused by: java.io.IOException: 远程主机强迫关闭了一个现有的连接。
eclipse连接远程Hadoop报错,Caused by: java.io.IOException: 远程主机强迫关闭了一个现有的连接.全部报错信息如下: Exception in thread & ...
- [博弈]ZOJ3591 Nim
题意: 给了一串数,个数不超过$10^5$,这串数是通过题目给的一段代码来生成的 int g = S; ; i<N; i++) { a[i] = g; ) { a[i] = g = W; } = ...
- centos更新163源并升级内核
使用说明 首先备份/etc/yum.repos.d/CentOS-Base.repo mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/Cen ...
- Android开发之注解式框架ButterKnife的使用
ButterKnife官网 其实ButterKnife的注解式,与xUtils的ViewUtils模块基本上差不多,只要用过xUtils,这个框架基本上就会了. 一.原理. 最近发现一个很好用的开源框 ...
- Eclipse优化
未特别说明,以下均处理在Window->Preferences下 General列表下 Startup and Shutdown可以去掉一些不必要的启动项 怎样才能知道哪些启动项有用呢?我现在把 ...
- hdu4630No Pain No Game (多校3)(树状数组)
http://acm.hdu.edu.cn/showproblem.php?pid=4630 给的题解没看懂..搜解题报告看 了N久 终于在cui大神的指点下 搞明白咋回事了 将1-N中的每个数ai ...
- Compass 编译.scss文件的问题
compass 命令编译scss文件存在一个问题: 不能对"_"下划线开头的scss文件名称的文件进行编译.将"_"去掉就可以啦