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) 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
1
6 9
1 2 5
2 3 5
3 1 10
3 4 12
4 1 8
4 6 11
5 4 7
5 6 9
6 5 4
 
Sample Output
42
 
题意:和hdu 1853题意和解法几乎一样,但是这题我看英文硬是没看懂。。。题意就是n个城市,每个城市都必须在一个环里面并且也只能出现在一个环里面?问最小的花费是多少?
题解:解法一:最小费用最大流:要去重 不然TLE。每个点只能出现一次,那么一个点容量限制为1,然后拆点跑最小费用最大流即可.
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std;
const int INF = ;
const int N = ;
const int M = ;
struct Edge{
int u,v,cap,cost,next;
}edge[M];
int head[N],tot,low[N],pre[N];
int total ;
bool vis[N];
int flag[N][N];
void addEdge(int u,int v,int cap,int cost,int &k){
edge[k].u=u,edge[k].v=v,edge[k].cap = cap,edge[k].cost = cost,edge[k].next = head[u],head[u] = k++;
edge[k].u=v,edge[k].v=u,edge[k].cap = ,edge[k].cost = -cost,edge[k].next = head[v],head[v] = k++;
}
void init(){
memset(head,-,sizeof(head));
tot = ;
}
bool spfa(int s,int t,int n){
memset(vis,false,sizeof(vis));
for(int i=;i<=n;i++){
low[i] = (i==s)?:INF;
pre[i] = -;
}
queue<int> q;
q.push(s);
while(!q.empty()){
int u = q.front();
q.pop();
vis[u] = false;
for(int k=head[u];k!=-;k=edge[k].next){
int v = edge[k].v;
if(edge[k].cap>&&low[v]>low[u]+edge[k].cost){
low[v] = low[u] + edge[k].cost;
pre[v] = k; ///v为终点对应的边
if(!vis[v]){
vis[v] = true;
q.push(v);
}
}
}
}
if(pre[t]==-) return false;
return true;
}
int MCMF(int s,int t,int n){
int mincost = ,minflow,flow=;
while(spfa(s,t,n))
{
minflow=INF+;
for(int i=pre[t];i!=-;i=pre[edge[i].u])
minflow=min(minflow,edge[i].cap);
flow+=minflow;
for(int i=pre[t];i!=-;i=pre[edge[i].u])
{
edge[i].cap-=minflow;
edge[i^].cap+=minflow;
}
mincost+=low[t]*minflow;
}
total=flow;
return mincost;
}
int n,m;
int main(){
int tcase;
scanf("%d",&tcase);
while(tcase--){
init();
scanf("%d%d",&n,&m);
int src = ,des = *n+;
for(int i=;i<=n;i++){
addEdge(src,i,,,tot);
addEdge(i+n,des,,,tot);
}
memset(flag,-,sizeof(flag));
for(int i=;i<=m;i++){ ///去重
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
if(flag[u][v]==-||w<flag[u][v]){
flag[u][v] = w;
}
}
for(int i=;i<=n;i++){
for(int j=;j<=n;j++){
if(flag[i][j]!=-){
addEdge(i,j+n,,flag[i][j],tot);
}
}
}
int mincost = MCMF(src,des,*n+);
if(total!=n) printf("-1\n");
else printf("%d\n",mincost);
}
}

题解二:KM算法,也是将一个点看成两个点,算最优匹配即可.

#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std;
const int INF = ;
const int N = ;
int graph[N][N];
int lx[N],ly[N];
int linker[N];
bool x[N],y[N];
int n,m;
void init(){
memset(lx,,sizeof(lx));
memset(ly,,sizeof(ly));
memset(linker,-,sizeof(linker));
for(int i=;i<=n;i++){
for(int j=;j<=n;j++){
if(lx[i]<graph[i][j]) lx[i] = graph[i][j];
}
}
}
bool dfs(int u){
x[u] = true;
for(int i=;i<=n;i++){
if(!y[i]&&graph[u][i]==lx[u]+ly[i]){
y[i] = true;
if(linker[i]==-||dfs(linker[i])){
linker[i] = u;
return true;
}
}
}
return false;
}
int KM(){
int sum = ;
init();
for(int i=;i<=n;i++){
while(){
memset(x,false,sizeof(x));
memset(y,false,sizeof(y));
if(dfs(i)) break;
int d = INF;
for(int j=;j<=n;j++){
if(x[j]){
for(int k=;k<=n;k++){
if(!y[k]) d = min(d,lx[j]+ly[k]-graph[j][k]);
}
}
}
if(d==INF) break;
for(int j=;j<=n;j++){
if(x[j]) lx[j]-=d;
if(y[j]) ly[j]+=d;
}
}
}
for(int i=;i<=n;i++){
sum+=graph[linker[i]][i];
}
return sum;
}
int main()
{
int tcase;
scanf("%d",&tcase);
while(tcase--){
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++){
for(int j=;j<=n;j++){
graph[i][j] = -INF;
}
}
for(int i=;i<=m;i++){
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
graph[u][v] = max(graph[u][v],-w);
}
int ans = KM();
printf("%d\n",-ans);
}
return ;
}

不去重之后还可以很快跑过去的某大牛的模板.

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#include<set>
#include<vector>
#include<map>
#include<queue>
#include<climits>
#include<assert.h>
#include<functional>
using namespace std;
const int maxn=;
const int INF=;
typedef pair<int,int> P; struct edge
{
int to,cap,cost,rev;
edge(int t,int c,int co,int r)
:to(t),cap(c),cost(co),rev(r){}
edge(){}
}; int V;//the number of points
vector<edge>G[maxn];
int h[maxn];
int dist[maxn];
int prevv[maxn],preve[maxn];
void add_edge(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()-));
} void clear()
{
for(int i=;i<V;i++) G[i].clear();
} int min_cost_flow(int s,int t,int f)
{
int res=,k=f;
fill(h,h+V,);//如果下标从1开始,就要+1
while(f>)
{
priority_queue<P,vector<P>,greater<P> >que;
fill(dist,dist+V,INF);
dist[s]=;
que.push(P(,s));
while(!que.empty())
{
P cur=que.top();que.pop();
int v=cur.second;
if(dist[v]<cur.first) continue;
for(int i=;i<G[v].size();i++)
{
edge &e=G[v][i];
if(e.cap>&&dist[e.to]>dist[v]+e.cost+h[v]-h[e.to])
{
dist[e.to]=dist[v]+e.cost+h[v]-h[e.to];
prevv[e.to]=v;
preve[e.to]=i;
que.push(P(dist[e.to],e.to));
}
}
}
if(dist[t]==INF)
{
return -;
}
for(int v=;v<V;v++) h[v]+=dist[v];//从0还是1开始需要结合题目下标从什么开始 int d=f;
for(int v=t;v!=s;v=prevv[v])
{
d=min(d,G[prevv[v]][preve[v]].cap);
}
f-=d;
res+=d*h[t];
for(int v=t;v!=s;v=prevv[v])
{
edge &e=G[prevv[v]][preve[v]];
e.cap-=d;
G[v][e.rev].cap+=d;
}
}
return res;
} int n,m;
int main(){
int tcase;
scanf("%d",&tcase);
while(tcase--){
scanf("%d%d",&n,&m);
clear();
V=*n+;
int src = ,des = *n+;
for(int i=;i<=n;i++){
add_edge(src,i,,);
add_edge(i+n,des,,);
}
for(int i=;i<=m;i++){
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
add_edge(u,n+v,,w);
}
int mincost = min_cost_flow(src,des,n);
printf("%d\n",mincost);
}
}

hdu 3488(KM算法||最小费用最大流)的更多相关文章

  1. hdu 3395(KM算法||最小费用最大流(第二种超级巧妙))

    Special Fish Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Tota ...

  2. 图论算法-最小费用最大流模板【EK;Dinic】

    图论算法-最小费用最大流模板[EK;Dinic] EK模板 const int inf=1000000000; int n,m,s,t; struct node{int v,w,c;}; vector ...

  3. hdu 1533 Going Home 最小费用最大流

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1533 On a grid map there are n little men and n house ...

  4. HDU 5988.Coding Contest 最小费用最大流

    Coding Contest Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)To ...

  5. hdu 3667(拆边+最小费用最大流)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3667 思路:由于花费的计算方法是a*x*x,因此必须拆边,使得最小费用流模板可用,即变成a*x的形式. ...

  6. HDU–5988-Coding Contest(最小费用最大流变形)

    Coding Contest Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)To ...

  7. POJ 2195 & HDU 1533 Going Home(最小费用最大流)

    这就是一道最小费用最大流问题 最大流就体现到每一个'm'都能找到一个'H',但是要在这个基础上面加一个费用,按照题意费用就是(横坐标之差的绝对值加上纵坐标之差的绝对值) 然后最小费用最大流模板就是再用 ...

  8. hdu 1533 Going Home 最小费用最大流 入门题

    Going Home Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Tota ...

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

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

随机推荐

  1. Javascript计算世界完全对称日

    今天是 2011-11-02 日,微博啊.G+啊什么的都传是世界完全对称日,还说是多少年一遇的.下面写个 JavaScript 小程序,看看是否真的N年一遇.计算范围在公元2000年到3000年. 名 ...

  2. mybatis <where>、<set>、<trim>、<sql>、<foreach>标签的使用

    转:http://www.cnblogs.com/lixiujie/p/5766669.html <resultMap>标签的使用:这个类似于hibernte用于映射我们创建的vo对象与数 ...

  3. redis 查看所有键值

    zb@zb-computer:/home/wwwroot/default/lion/Admin$ /usr/local/redis/bin/redis-cli 127.0.0.1:6379> k ...

  4. MySql 利用函数 查询所有子节点

    前提:mysql  函数  find_in_set(str,strlist), cast(value as type)   一.find_in_set(str,strlist):如果字符串str是在的 ...

  5. 替换Jar包中的一个文件 Replace a file in a JAR

    例如: jar uf myJarFile.jar com\vsoft\servlet\myServlet.class This will replace the class myServlet.cla ...

  6. js 拖动滑块验证

    备注:拖动滑块时尽量平移,chrome浏览器上没有卡顿情况,但是搜狗极速模式和360极速模式都遇到了卡顿,拖不动情况,应是浏览器内部对事件响应速度导致吧. JS代码: ;(function ($,wi ...

  7. Item 4 ----通过私有构造器强化不可实例化的能力

    场景: 在创建工具类的时候,大部分是无需实例化的,实例化对它们没有意义.在这种情况下,创建的类,要确保它是不可以实例化的.   存在问题: 在创建不可实例化的类时,虽然没有定义构造器.但是,客户端在使 ...

  8. 苹果API常用英语名词---iOS-Apple苹果官方文档翻译

    本系列所有开发文档翻译链接地址:iOS7开发-Apple苹果iPhone开发Xcode官方文档翻译PDF下载地址 苹果API常用英语名词0. indicating 决定1.in order to 以便 ...

  9. Spring注解概览(数漫江湖)

    从Java5.0开始,Java开始支持注解.Spring做为Java生态中的领军框架,从2.5版本后也开始支持注解.相比起之前使用xml来配置Spring框架,使用注解提供了更多的控制Spring框架 ...

  10. 聂老师的考验(反向bfs)

    题目链接:http://113.240.233.2:8081/JudgeOnline/problem.php?id=1121 这个题看起来要多次使用bfs,其实只要换个思维就会发现这就是一个简单的bf ...