Tour
Time Limit: 1000MS   Memory Limit: 65536K
Total Submissions: 3408   Accepted: 1513

Description

John Doe, a skilled pilot, enjoys traveling. While on vacation, he rents a small plane and starts visiting beautiful places. To save money, John must determine the shortest closed tour that connects his destinations. Each destination
is represented by a point in the plane pi = < xi,yi >. John uses the following strategy: he starts from the leftmost point, then he goes strictly left to right to the rightmost point, and then he goes strictly right back to the starting point. It is known
that the points have distinct x-coordinates.

Write a program that, given a set of n points in the plane, computes the shortest closed tour that connects the points according to John's strategy.

Input

The program input is from a text file. Each data set in the file stands for a particular set of points. For each set of points the data set contains the number of points, and the point coordinates in ascending order of the x coordinate.
White spaces can occur freely in input. The input data are correct.

Output

For each set of data, your program should print the result to the standard output from the beginning of a line. The tour length, a floating-point number with two fractional digits, represents the result. An input/output sample
is in the table below. Here there are two data sets. The first one contains 3 points specified by their x and y coordinates. The second point, for example, has the x coordinate 2, and the y coordinate 3. The result for each data set is the tour length, (6.47
for the first data set in the given example).

Sample Input

3
1 1
2 3
3 1
4
1 1
2 3
3 1
4 2

Sample Output

一旅行商从左向右走到最右边,然后再返回原来出发点的最短路径。

两种做法,第一种dp。dp[i][j]表示以i。j结尾的两条不相交的路径如果i一定大于j。i有两种选择,与i-1相连。不与i-1相连,然后dp

代码:

#include <stdio.h>
#include <string.h>
#include <iostream>
#include <math.h>
#include <queue>
#include <set>
#include <algorithm>
#include <stdlib.h>
using namespace std;
#define ll int
#define N 1005
#define inf 100000000
struct node{
double x, y;
bool operator<(const node&a)const{
if(a.x==x)return a.y>y;
return a.x>x;
}
}p[N];
double Dis(node a, node b){return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));}
int n;
double dis[N][N],dp[N][N];
int main(){
ll i, j, u, v;
while(~scanf("%d",&n)){//dp[i][j]表示以i。j为结尾的两条不相交的路径
for(i=1;i<=n;i++)scanf("%lf %lf",&p[i].x,&p[i].y);
sort(p+1,p+n+1);
for(i=1;i<=n;i++)for(j=1;j<=n;j++)dis[i][j] = Dis(p[i],p[j]), dp[i][j] = inf; dp[1][1] = 0;
for(i=2;i<=n;i++)
{
for(j = 1;j < i; j++)
{
dp[i][j] = min(dp[i-1][j]+dis[i][i-1], dp[i][j]);//i不与i-1相连,
dp[i][i-1] = min(dp[i-1][j]+dis[j][i], dp[i][i-1]);//i与i-1相连。
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++)cout<<dp[i][j]<<" ";
cout<<endl;
}
printf("%.2lf\n",dp[n][n-1]+dis[n][n-1]);
}
return 0;
}

费用流,把每个点拆点,中间连流量为1,费用为负无穷的边。代表该点必须选择,两两之间连流量为1,费用为两点距离的边,起点,终点连边,流量为1,费用为0.

代表能够增广两次。

代码:

/* ***********************************************
Author :_rabbit
Created Time :2014/5/17 9:42:51
File Name :6.cpp
************************************************ */
#pragma comment(linker, "/STACK:102400000,102400000")
#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <sstream>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <string>
#include <time.h>
#include <math.h>
#include <queue>
#include <stack>
#include <set>
#include <map>
using namespace std;
#define INF 1001000
#define eps 1e-8
#define pi acos(-1.0)
typedef long long ll;
const int maxn=4010;
const int maxm=200000;
struct Edge{
int next,to,cap;
double cost;
Edge(int _next=0,int _to=0,int _cap=0,double _cost=0){
next=_next;to=_to;cap=_cap;cost=_cost;
}
}edge[maxm];
int head[maxn],vis[maxn],pre[maxn],n,tol;
double dis[maxn];
void addedge(int u,int v,int cap,double cost){
edge[tol]=Edge(head[u],v,cap,cost);head[u]=tol++;
edge[tol]=Edge(head[v],u,0,-cost);head[v]=tol++;
}
bool spfa(int s,int t){
queue<int> q;
for(int i=0;i<=n;i++)
dis[i]=INF,vis[i]=0,pre[i]=-1;
dis[s]=0;vis[s]=1;q.push(s);
while(!q.empty()){
int u=q.front();q.pop();vis[u]=0;
// cout<<"u="<<u<<" "<<dis[u]<<endl;
for(int i=head[u];i!=-1;i=edge[i].next){
int v=edge[i].to;
if(edge[i].cap>0&&dis[v]>dis[u]+edge[i].cost){
dis[v]=dis[u]+edge[i].cost;
pre[v]=i;
if(!vis[v])vis[v]=1,q.push(v);
}
}
}
if(pre[t]==-1)return 0;
return 1;
}
void fun(int s,int t,int &flow,double &cost){
flow=0;cost=0;
while(spfa(s,t)){
int MIN=INF;
for(int i=pre[t];i!=-1;i=pre[edge[i^1].to])
if(MIN>edge[i].cap)MIN=edge[i].cap;
for(int i=pre[t];i!=-1;i=pre[edge[i^1].to])
edge[i].cap-=MIN,edge[i^1].cap+=MIN,cost+=edge[i].cost*MIN;
flow+=MIN;
}
}
struct Point{
double x,y;
}pp[10000];
double dist(Point a,Point b){
double ss=a.x-b.x;
double tt=a.y-b.y;
return sqrt(ss*ss+tt*tt);
}
int main(){
int m;
// freopen("data.out","w",stdout);
while(cin>>m){
memset(head,-1,sizeof(head));tol=0;
for(int i=1;i<=m;i++)cin>>pp[i].x>>pp[i].y;
for(int i=1;i<=m;i++){
for(int j=i+1;j<=m;j++){
double dd=dist(pp[i],pp[j]);
addedge(i+m,j,1,dd);
}
addedge(i,i+m,1,-INF);
}
addedge(1,m+1,1,0);
addedge(m,2*m,1,0);
n=2*m;
int flow;double cost;
fun(1,2*m,flow,cost);
printf("%.2lf\n",cost+m*INF);
}
return 0;
}

POJ 2677 旅行商问题 双调dp或者费用流的更多相关文章

  1. POJ 3686 The Windy's (费用流)

    [题目链接] http://poj.org/problem?id=3686 [题目大意] 每个工厂对于每种玩具的加工时间都是不同的, 并且在加工完一种玩具之后才能加工另一种,现在求加工完每种玩具的平均 ...

  2. BZOJ 2424 DP OR 费用流

    思路: 1.DP f[i][j]表示第i个月的月底 还剩j的容量 转移还是相对比较好想的-- f[i][j+1]=min(f[i][j+1],f[i][j]+d[i]); if(j>=u[i+1 ...

  3. luogu P5470 [NOI2019]序列 dp 贪心 费用流 模拟费用流

    LINK:序列 考虑前20分 容易想到爆搜. 考虑dp 容易设\(f_{i,j,k,l}\)表示前i个位置 选了j对 且此时A选择了k个 B选择了l个的最大值.期望得分28. code //#incl ...

  4. [CF1525D] Armchairs (DP / 模拟费用流)

    题面简述 一条线上等距地分布着 n n n 老鼠和 m m m 洞( m ≥ n m\geq n m≥n),这连续 n + m n+m n+m 个位置上要么是老鼠要么是洞,一个老鼠进一个洞,代价是所有 ...

  5. poj 3422 Kaka's Matrix Travels 费用流

    题目链接 给一个n*n的矩阵, 从左上角出发, 走到右下角, 然后在返回左上角,这样算两次. 一共重复k次, 每个格子有值, 问能够取得的最大值是多少, 一个格子的值只能取一次, 取完后变为0. 费用 ...

  6. POJ 2175:Evacuation Plan(费用流消圈算法)***

    http://poj.org/problem?id=2175 题意:有n个楼,m个防空洞,每个楼有一个坐标和一个人数B,每个防空洞有一个坐标和容纳量C,从楼到防空洞需要的时间是其曼哈顿距离+1,现在给 ...

  7. 【BZOJ-4213】贪吃蛇 有上下界的费用流

    4213: 贪吃蛇 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 58  Solved: 24[Submit][Status][Discuss] Desc ...

  8. 洛谷 1004 dp或最大费用流

    思路: dp方法: 设dp[i][j][k][l]为两条没有交叉的路径分别走到(i,j)和(k,l)处最大价值. 则转移方程为 dp[i][j][k][l]=max(dp[i-1][j][k-1][l ...

  9. POJ 2175 Evacuation Plan (费用流,负环,消圈法,SPFA)

    http://poj.org/problem?id=2175 Evacuation Plan Time Limit: 1000MS   Memory Limit: 65536K Total Submi ...

随机推荐

  1. 解决:解压zip文件却变成cpgz文件

    众所周知,zip是一种压缩文件格式,MAC OS默认支持的文件格式,当时偶尔当你打开zip文件想要解压时,却自动变成了cpgz文件而没有解压,再双击这个cpgz文件,Archive Utility又会 ...

  2. [翻译] Canvas 不用写代码的动画

    Canvas 不用写代码的动画 https://github.com/CanvasPod/Canvas Canvas is a project to simplify iOS development ...

  3. 《Android传感器高级编程》

    <Android传感器高级编程> 基本信息 原书名:Professional Android Sensor Programming 原出版社: Wrox 作者: (美)米内特(Greg M ...

  4. sql 的 DATE_FORMATE()函数

    定义和用法 DATE_FORMAT() 函数用于以不同的格式显示日期/时间数据. 语法 DATE_FORMAT(date,format) date 参数是合法的日期.format 规定日期/时间的输出 ...

  5. https://github.com/wytings

    博客中写了很多比较杂乱的东西,有时候可能一时看不出效果,毕竟代码问题确实是 “Talk is cheap. Show me the code” 所以,就开了一个github,把一些日常开发和使用的工具 ...

  6. Linux C 网络编程 - 获取本地 ip 地址,mac,通过域名获取对应的 ip

    获取本地 ip 地址,mac,通过域名获取对应的 ip, 是网络编程可能遇到的比较常见的操作了,所以总结如下(封装了3个函数), 直接上代码: #include <stdio.h> #in ...

  7. 实用Linux命令

    lsof -i:6379 查看某个端口的程序有没有起起来. netstat -tnlp 可以查看监听的端口,其中l是listening, p是显示program, n是显示ip而不是name, t看起 ...

  8. C#装饰者模式实例代码

    using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace 装饰者 ...

  9. jquery easyui validatebox remote使用

    validatebox 的validateType可以是一下3个格式: 1字符串 2数组,应用多个验证 3对象,每个key是一个验证名称value是验证的数组参数 下面是代码示例 <input ...

  10. (LeetCode 49)Anagrams

    Given an array of strings, return all groups of strings that are anagrams. Note: All inputs will be ...