因为每个点只能经过一次 所以考虑拆点

这题有坑,有重边。。

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 费用流)的更多相关文章

  1. Hdu 3488 Tour (KM 有向环覆盖)

    题目链接: Hdu 3488 Tour 题目描述: 有n个节点,m条有权单向路,要求用一个或者多个环覆盖所有的节点.每个节点只能出现在一个环中,每个环中至少有两个节点.问最小边权花费为多少? 解题思路 ...

  2. hdoj 3488 Tour 【最小费用最大流】【KM算法】

    Tour Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others) Total Submi ...

  3. hdu 1533 KM或费用流

    以前用KM写过,现在再用费用流写. #include <iostream> #include <cstdio> #include <cstring> #includ ...

  4. 【进阶——最小费用最大流】hdu 1533 Going Home (费用流)Pacific Northwest 2004

    题意: 给一个n*m的矩阵,其中由k个人和k个房子,给每个人匹配一个不同的房子,要求所有人走过的曼哈顿距离之和最短. 输入: 多组输入数据. 每组输入数据第一行是两个整型n, m,表示矩阵的长和宽. ...

  5. HDU 5644 King's Pilots 费用流

    King's Pilots 题目连接: http://acm.hdu.edu.cn/showproblem.php?pid=5644 Description The military parade w ...

  6. HDU 3667 Transportation(网络流之费用流)

    题目地址:HDU 3667 这题的建图真是巧妙...为了保证流量正好达到k.须要让每一次增广到的流量都是1,这就须要把每一条边的流量都是1才行.可是每条边的流量并非1,该怎么办呢.这个时候能够拆边,反 ...

  7. HDU - 5406 CRB and Apple (费用流)

    题意:对于给定的物品,求两个在高度上单调不递增,权值上单调不递减的序列,使二者长度之和最大. 分析:可以用费用流求解,因为要求长度和最大,视作从源点出发的流量为2的费用流,建负权边,每个物品只能取一次 ...

  8. 图论(二分图,KM算法):HDU 3488 Tour

    Tour Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others)Total Submis ...

  9. HDU 3488 Tour (最大权完美匹配)【KM算法】

    <题目链接> 题目大意:给出n个点m条单向边边以及经过每条边的费用,让你求出走过一个哈密顿环(除起点外,每个点只能走一次)的最小费用.题目保证至少存在一个环满足条件. 解题分析: 因为要求 ...

随机推荐

  1. Android 图片缩放

    以下演示将一个ImageView的高度设置为两倍: 布局文件main.xml <?xml version="1.0" encoding="utf-8"?& ...

  2. MSSQLServer基础01(数据类型)

    数据库设计:范式 现阶段,必须遵守满足3NF 1范式:列的原子性,即列不可再拆分 2范式:表中不能描述多个信息,不能有数据冗余 3范式:引用其它表的主键信息 数据类型的意义: 1>提高效率.(减 ...

  3. SGU111 Very simple problem

    多少个平方数小于等于X,二分. PS:java BigInteger. import java.util.*; import java.math.*; public class Solution { ...

  4. matlab 中保存某几个变量

    save  AOA.mat dingjiao RMSE%保存变量dingjiao,RMSE于AOA.mat clear all;%当删除所有数据之后 load AOA.mat%还可以读出这两个变量的数 ...

  5. XMPP聊天客户端环境搭建

    1.服务器选择:ejabberd,具体安装过程请参考:http://blog.csdn.net/linhanmin/article/details/9876819 2.客户端配置: 采用xmppfra ...

  6. 去除html标签 正则 <.+?> 解释

    http://baike.baidu.com/link?url=2zORJF9GOjU8AkmuHDLz9cyl9yiL68PdW3frayzLwWQhDvDEM51V_CcY_g1mZ7OPdcq8 ...

  7. C++内存中的封装、继承、多态(下)

    上篇讲述了内存中的封装模型,下篇我们讲述一下继承和多态. 二.继承与多态情况下的内存布局 由于继承下的内存布局以及构造过程很多书籍都讲得比较详细,所以这里不细讲.重点讲多态. 继承有以下这几种情况: ...

  8. mysqld -install命令时出现install/remove of the service denied错误的原因和解决办法

    原因:没有使用管理员权限 解决方法:使用管理员权限打开cmd,然后运行mysqld -install,服务安装成功

  9. poj 2635 The Embarrassed Cryptographer(数论)

    题目:http://poj.org/problem?id=2635 高精度求模  同余模定理. 题意: 给定一个大数K,K是两个大素数的乘积的值.再给定一个int内的数L 问这两个大素数中最小的一个是 ...

  10. My97 DatePicker使用之自定义事件

    参考网站:http://www.my97.net/dp/demo/resource/2.5.asp 自定义事件 如果你需要做一些附加的操作,你也不必担心,日期控件自带的自定义事件可以满足你的需求.此外 ...