hdoj 3488 Tour 【最小费用最大流】【KM算法】
TourTime Limit: 3000/1000 MS (Java/Others) Memory Limit: 65535/65535 K (Java/Others)
Problem Description
In the kingdom of Henryy, there are N (2 <= N <= 200) cities, with M (M <= 30000) one-way roads connecting them. You are lucky enough to have a chance to have a tour in the kingdom. The route should be designed as: The route should contain one or more loops.
(A loop is a route like: A->B->……->P->A.) Every city should be just in one route. A loop should have at least two cities. In one route, each city should be visited just once. (The only exception is that the first and the last city should be the same and this city is visited twice.) The total distance the N roads you have chosen should be minimized.
Input
An integer T in the first line indicates the number of the test cases.
In each test case, the first line contains two integers N and M, indicating the number of the cities and the one-way roads. Then M lines followed, each line has three integers U, V and W (0 < W <= 10000), indicating that there is a road from U to V, with the distance of W. It is guaranteed that at least one valid arrangement of the tour is existed. A blank line is followed after each test case.
Output
For each test case, output a line with exactly one integer, which is the minimum total distance.
Sample Input
Sample Output
|
用费用流G++能够卡过,C++会超时。
用KM应该非常快吧,如今先刷费用流,过几天再好好做KM。
题意:给出n个点m条单向边边以及经过每条边的费用,让你求出走过一个哈密顿环(除起点外,每一个点仅仅能走一次)的最小费用。题目保证至少存在一个环满足条件,事实上推断成环仅仅须要推断是否满流就可以。
思路: 把每一个点i拆分成左点i和右点i+N
1。超级源点连左点。容量为1,费用为0
2。全部右点连超级汇点,容量为1。费用为0
3,每条单向边—— 起点左点 连 终点右点 容量为1,费用为边权。
最后跑一下费用流即可了。
注意重边的处理,不去重费用流会超时,还有要用G++提交。 抽出时间再补上KM的AC代码。
费用流AC代码:
#include <cstdio>
#include <cstring>
#include <queue>
#include <stack>
#include <vector>
#include <algorithm>
#define MAXN 400+10
#define MAXM 70000+10
#define INF 0x3f3f3f3f
using namespace std;
struct Edge
{
int from, to, cap, flow, cost, next;
};
Edge edge[MAXM];
int head[MAXN], edgenum;
int pre[MAXN], dist[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, int c)//必须去重!!! {
int i;
for(i = head[u]; i != -1; i = edge[i].next)
{
if(edge[i].to == v)
break;
}
if(i != -1)
{
if(edge[i].cost > c)
edge[i].cost = c, edge[i^1].cost = -c;
return ;
}
Edge E1 = {u, v, w, 0, c, head[u]};
edge[edgenum] = E1;
head[u] = edgenum++;
Edge E2 = {v, u, 0, 0, -c, head[v]};
edge[edgenum] = E2;
head[v] = edgenum++;
}
void getMap()
{
scanf("%d%d", &N, &M);
int a, b, c;
source = 0, sink = 2 * N + 1;
//把每一个点i拆分成左点i和右点i+N
//超级源点连左点。容量为1,费用为0
//全部右点连超级汇点。容量为1,费用为0
//单向边: 起点左点连终点右点 容量为1,费用为边权
for(int i = 1; i <= N; i++)
addEdge(source, i, 1, 0),
//addEdge(i, i + N, 1, 0),
addEdge(i + N, sink, 1, 0);
while(M--)
{
scanf("%d%d%d", &a, &b, &c);
addEdge(a, b+N, 1, c);
}
}
bool SPFA(int s, int t)
{
queue<int> Q;
memset(dist, INF, sizeof(dist));
memset(vis, false, sizeof(vis));
memset(pre, -1, sizeof(pre));
dist[s] = 0;
vis[s] = true;
Q.push(s);
while(!Q.empty())
{
int u = Q.front();
Q.pop();
vis[u] = false;
for(int i = head[u]; i != -1; i = edge[i].next)
{
Edge E = edge[i];
if(dist[E.to] > dist[u] + E.cost && E.cap > E.flow)
{
dist[E.to] = dist[u] + E.cost;
pre[E.to] = i;
if(!vis[E.to])
{
vis[E.to] = true;
Q.push(E.to);
}
}
}
}
return pre[t] != -1;
}
void MCMF(int s, int t, int &cost, int &flow)
{
flow = cost = 0;
while(SPFA(s, t))
{
int Min = INF;
for(int i = pre[t]; i != -1; i = pre[edge[i^1].to])
{
Edge E = edge[i];
Min = min(Min, E.cap - E.flow);
}
for(int i = pre[t]; i != -1; i = pre[edge[i^1].to])
{
edge[i].flow += Min;
edge[i^1].flow -= Min;
cost += edge[i].cost * Min;
}
flow += Min;
}
}
int main()
{
int t;
scanf("%d", &t);
while(t--)
{
init();
getMap();
int cost, flow;
MCMF(source, sink, cost, flow);
printf("%d\n", cost);
}
return 0;
}
KM算法:重刷
边权取负。注意重边的处理。
AC代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
#define INF 0x3f3f3f3f
#define MAXN 210
using namespace std;
int lx[MAXN], ly[MAXN];
int Map[MAXN][MAXN];
bool visx[MAXN], visy[MAXN];
int slack[MAXN];
int match[MAXN];
int N, M;
void getMap()
{
for(int i = 1; i <= N; i++)
{
for(int j = 1; j <= N; j++)
Map[i][j] = -INF;
}
int a, b, c;
while(M--)
{
scanf("%d%d%d", &a, &b, &c);
if(-c > Map[a][b])
Map[a][b] = -c;
}
}
int DFS(int x)
{
visx[x] = true;
for(int y = 1; y <= N; y++)
{
if(visy[y]) continue;
int t = lx[x] + ly[y] - Map[x][y];
if(t == 0)
{
visy[y] = true;
if(match[y] == -1 || DFS(match[y]))
{
match[y] = x;
return 1;
}
}
else if(slack[y] > t)
slack[y] = t;
}
return 0;
}
void KM()
{
memset(match, -1, sizeof(match));
memset(ly, 0, sizeof(ly));
for(int x = 1; x <= N; x++)
{
lx[x] = -INF;
for(int y = 1; y <= N; y++)
lx[x] = max(lx[x], Map[x][y]);
}
for(int x = 1; x <= N; x++)
{
for(int i = 1; i <= N; i++)
slack[i] = INF;
while(1)
{
memset(visx, false, sizeof(visx));
memset(visy, false, sizeof(visy));
if(DFS(x)) break;
int d = INF;
for(int i = 1; i <= N; i++)
{
if(!visy[i] && slack[i] < d)
d = slack[i];
}
for(int i = 1; i <= N; i++)
{
if(visx[i])
lx[i] -= d;
}
for(int i = 1; i <= N; i++)
{
if(visy[i])
ly[i] += d;
else
slack[i] -= d;
}
}
}
int ans = 0;
for(int i = 1; i <= N; i++)
ans += Map[match[i]][i];
printf("%d\n", -ans);
}
int main()
{
int t;
scanf("%d", &t);
while(t--)
{
scanf("%d%d", &N, &M);
getMap();
KM();
}
return 0;
}
hdoj 3488 Tour 【最小费用最大流】【KM算法】的更多相关文章
- TZOJ 1513 Farm Tour(最小费用最大流)
描述 When FJ's friends visit him on the farm, he likes to show them around. His farm comprises N (1 &l ...
- Farm Tour(最小费用最大流模板)
Farm Tour Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 18150 Accepted: 7023 Descri ...
- POJ2135 Farm Tour —— 最小费用最大流
题目链接:http://poj.org/problem?id=2135 Farm Tour Time Limit: 1000MS Memory Limit: 65536K Total Submis ...
- poj 2351 Farm Tour (最小费用最大流)
Farm Tour Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 17230 Accepted: 6647 Descri ...
- poj 2135 Farm Tour 最小费用最大流建图跑最短路
题目链接 题意:无向图有N(N <= 1000)个节点,M(M <= 10000)条边:从节点1走到节点N再从N走回来,图中不能走同一条边,且图中可能出现重边,问最短距离之和为多少? 思路 ...
- POJ 2135 Farm Tour [最小费用最大流]
题意: 有n个点和m条边,让你从1出发到n再从n回到1,不要求所有点都要经过,但是每条边只能走一次.边是无向边. 问最短的行走距离多少. 一开始看这题还没搞费用流,后来搞了搞再回来看,想了想建图不是很 ...
- hdu 1853 Cyclic Tour 最小费用最大流
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1853 There are N cities in our country, and M one-way ...
- [poj] 1235 Farm Tour || 最小费用最大流
原题 费用流板子题. 费用流与最大流的区别就是把bfs改为spfa,dfs时把按deep搜索改成按最短路搜索即可 #include<cstdio> #include<queue> ...
- POJ-2516(最小费用最大流+MCMF算法)
Minimum Cost POJ-2516 题意就是有n个商家,有m个供货商,然后有k种商品,题目求的是满足商家的最小花费供货方式. 对于每个种类的商品k,建立一个超级源点和一个超级汇点.每个商家和源 ...
- POJ-2195(最小费用最大流+MCMF算法)
Going Home POJ-2195 这题使用的是最小费用流的模板. 建模的时候我的方法出现错误,导致出现WA,根据网上的建图方法没错. 这里的建图方法是每次到相邻点的最大容量为INF,而花费为1, ...
随机推荐
- MyEclipse中快速复制粘贴当前行的操作
- Spring Boot (8) 全局异常处理
服务层和dao层的最终异常会交给controller处理,控制层的异常则会记录日志系统. 新建一个类用来处理异常,名字随便GlobalDefaultExceptionHandler.java,加上@C ...
- jquery中的left和top
left 和 top /*1. 获取元素基于定位容器的位置*/ /*返回的是对象 属性 left top */ var position = $('.inner').position(); conso ...
- 酷派改变者S1(C105/C105-6/C105-8) 解锁BootLoader 并刷入recovery root
首先下载好工具链接:https://pan.baidu.com/s/1qZjOCUw 密码:u2dr 备用下载链接:https://pan.baidu.com/s/1pMlmAef 本篇教程教你如何傻 ...
- js-学习方法
1:多实践,找例子,看别人是如何实现的,然后自己去实现,然后谷歌百度,最后总结. 2:如何读js英文书:不是自己不会读,是被吓着了.自己吓自己. 英文不好的话,先不要挨着排的从头到尾读. 应该首先读目 ...
- fusionchart简单demo柱状图
本篇是柱状图,想要折线图的话,只要改变.swf文件就行. <div id="column2" style="width:240px; height:200px; m ...
- WEB笔记-让HTML5向下兼容的策略
//给新标签增加块级元素声明 article,aside,dialog,figure,fotter,header,legend,nav,section{display:block} //添加css兹瓷 ...
- c# ado.net eftity framework 返回多表查询结果
public static IQueryable GetWeiXinTuWenList() { using (var Model = new Model.WeiXinEntities()) { var ...
- JavaScript函数和window对象
一.什么是函数 函数的含义:类似于Java中的方法,是完成特定任务的代码语句块 使用更简单:不用定义属于某个类,直接使用 二.常用系统函数 parseInt ("字符串") ...
- Arduino 红外接收
一.实物图 二.例子代码 注:git clone https://github.com/z3t0/Arduino-IRremote.git 放到Arduino 的libraries目录下面 从遥控器 ...