POJ 2677 旅行商问题 双调dp或者费用流
Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 3408 | Accepted: 1513 |
Description
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
White spaces can occur freely in input. The input data are correct.
Output
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或者费用流的更多相关文章
- POJ 3686 The Windy's (费用流)
[题目链接] http://poj.org/problem?id=3686 [题目大意] 每个工厂对于每种玩具的加工时间都是不同的, 并且在加工完一种玩具之后才能加工另一种,现在求加工完每种玩具的平均 ...
- 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 ...
- luogu P5470 [NOI2019]序列 dp 贪心 费用流 模拟费用流
LINK:序列 考虑前20分 容易想到爆搜. 考虑dp 容易设\(f_{i,j,k,l}\)表示前i个位置 选了j对 且此时A选择了k个 B选择了l个的最大值.期望得分28. code //#incl ...
- [CF1525D] Armchairs (DP / 模拟费用流)
题面简述 一条线上等距地分布着 n n n 老鼠和 m m m 洞( m ≥ n m\geq n m≥n),这连续 n + m n+m n+m 个位置上要么是老鼠要么是洞,一个老鼠进一个洞,代价是所有 ...
- poj 3422 Kaka's Matrix Travels 费用流
题目链接 给一个n*n的矩阵, 从左上角出发, 走到右下角, 然后在返回左上角,这样算两次. 一共重复k次, 每个格子有值, 问能够取得的最大值是多少, 一个格子的值只能取一次, 取完后变为0. 费用 ...
- POJ 2175:Evacuation Plan(费用流消圈算法)***
http://poj.org/problem?id=2175 题意:有n个楼,m个防空洞,每个楼有一个坐标和一个人数B,每个防空洞有一个坐标和容纳量C,从楼到防空洞需要的时间是其曼哈顿距离+1,现在给 ...
- 【BZOJ-4213】贪吃蛇 有上下界的费用流
4213: 贪吃蛇 Time Limit: 5 Sec Memory Limit: 64 MBSubmit: 58 Solved: 24[Submit][Status][Discuss] Desc ...
- 洛谷 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 ...
- POJ 2175 Evacuation Plan (费用流,负环,消圈法,SPFA)
http://poj.org/problem?id=2175 Evacuation Plan Time Limit: 1000MS Memory Limit: 65536K Total Submi ...
随机推荐
- Debian 安装记录
1.蓝色标注是安装的部分或配置的. 作者:http://www.cppblog.com/jinglexy上海体育馆 2.linux 发行版测评网站:www.distrowatch.com 打 ...
- python爬虫beautifulsoup4系列4-子节点
前言 很多时候我们无法直接定位到某个元素,我们可以先定位它的父元素,通过父元素来找子元素就比较容易 一.子节点 1.以博客园首页的摘要为例:<div class="c_b_p_desc ...
- Cohen-SutherLand算法(编码算法)
转自:http://my.oschina.net/liqiong/blog/4921 Cohen-SutherLand算法(编码算法) 基本思想:对于每条线段P1P2,分为三种情况处理: (1)若 ...
- mongodb拷贝数据库copyDatabase()。实现释放磁盘空间的方法。
下面我们一起来看看关于mongodb拷贝数据库copyDatabase().实现释放磁盘空间的方法,希望文章对各位同学会有所帮助. db.copyDatabase("from",& ...
- javascript转换日期字符串为Date对象
把一个日期字符串如“2007-2-28 10:18:30”转换为Date对象: 1: var strArray=str.split(" "); var strDate=strArr ...
- 从头開始学 RecyclerView(六) LayoutManager
前言 在前面的文章中.每一个演示样例,都使用了LayoutManager,毕竟它是RecyclerView必不可少的一部分. LayoutManager,顾名思义,就是『布局管理器』. 使用例如以下代 ...
- 【Scroller】scrollTo scrollBy startScroll computeScroll 自定义ViewPage 简介 示例
简介 android.widget.Scroller是用于模拟scrolling行为,它是scrolling行为的一个帮助类.我们通常通过它的 startScroll 函数来设置一个 scrollin ...
- Spring定时器XML配置
spring-task.xml <?xml version="1.0" encoding="UTF-8"?> <beans xmlns=&qu ...
- 大端和小端(Big endian and Little endian)
一.大端和小端的问题 对于整型.长整型等数据类型,Big endian 认为第一个字节是最高位字节(按照从低地址到高地址的顺序存放数据的高位字节到低位字节):而 Little endian 则相反,它 ...
- ganglia组播和单播
ganglia快速开始向导(翻译自官方wiki) 发布于 2012 年 1 月 23 日 由 admin 2 comments发表评论 转自:http://cryinstall.com/?p=18 ...