双调TSP问题总结---poj 2677和usaco5.4 canada tour

来源:互联网 发布:数控编程员工资 编辑:程序博客网 时间:2024/05/13 00:49

双调TSP指的就是从最左边的城市出发,从左往右遍历一些城市,到达最右端,再从最右端从右往左返回出发城市,然后最优化某些东西。

poj 2677 就是要遍历所有的城市,最小化行走的距离(欧几里德距离)

usaco canada tour 就是每个城市最多遍历一次(出发点两次),最大化遍历的城市数量。

【解答】

显然从左往右,从右往左都是一样的,都可以变成从左往右。我们称前者为上行路线,后者为下行路线。

状态f[i][j]表示从出发点出发,上行路线最右端为i,下行路线最右端为j,同时我们规定,i在j的右边。

这样定义状态后,问题便迎刃而解。

例如poj 2677:

如果第i个城市归入上行路线,则 f[i][j]=min(f[i][j],f[i-1][j]+dis(a[i-1],a[i]));

否则归入下行路线:f[i][i-1]=min(f[i][i-1],f[i-1][j]+dis(a[j],a[i]));

这样,我们就把这个问题解决了。

【poj 2677 代码】

#include <iostream>#include <cstring>#include <string>#include <cstdio>#include <cmath>#include <algorithm>using namespace std;const int N=500;const double INF=1e10;struct point{    int x,y;}a[N];double f[N][N];double dis(point a,point b){    return sqrt(double((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)));}int main(){    int n,i,j;    double ans;    freopen("in","r",stdin);    while (scanf("%d",&n)!=EOF)    {        for (i=1;i<=n;i++)            scanf("%d%d",&a[i].x,&a[i].y);        for (i=1;i<=n;i++)            for (j=1;j<=n;j++)                f[i][j]=INF;        f[1][1]=0;        for (i=2;i<=n;i++)            for (j=1;j<i;j++)            {                f[i][j]=min(f[i][j],f[i-1][j]+dis(a[i-1],a[i]));                f[i][i-1]=min(f[i][i-1],f[i-1][j]+dis(a[j],a[i]));            }        ans=INF;        for (i=1;i<=n;i++)            ans=min(ans,f[n][i]+dis(a[n],a[i]));        printf("%.2f\n",ans);    }}

【canada tour 代码】

/*ID: ascii991PROG: tourLANG: C++*/#include <iostream>#include <cstring>#include <string>#include <cstdio>#include <algorithm>#include <map>using namespace std;const int N=103;map<string,int> Map;int f[N][N];bool a[N][N];int main(){    int i,j,k,m,n,ans=1;    string x,y;    freopen("tour.in","r",stdin);    freopen("tour.out","w",stdout);    cin >> n >> m;    for (i=1;i<=n;i++)    {        cin >> x;        Map[x]=i;    }    for (i=1;i<=m;i++)    {        cin >> x >> y;        a[Map[x]][Map[y]]=a[Map[y]][Map[x]]=true;    }    f[1][1]=1;    for (k=2;k<=n;k++)    {        for (i=1;i<k;i++)            for (j=1;j<=i;j++)            if (f[i][j]>0)            {                if (a[k][i]) f[k][j]=max(f[k][j],f[i][j]+1);                if (a[k][j]) f[k][i]=max(f[k][i],f[i][j]+1);            }    }    for (i=1;i<=n;i++)    if (a[n][i])        ans=max(ans,f[n][i]);    cout << ans << endl;}




原创粉丝点击