SPOJ - PUTNIK(想法+dp,好题)

来源:互联网 发布:ubuntu vi命令 编辑:程序博客网 时间:2024/06/10 12:08

PUTNIK - Putnik

no tags 

Chances are that you have probably already heard of the travelling salesman problem. If you have, then you are aware that it is an NP-hard problem because it lacks an efficient solution. Well, this task is an uncommon version of the famous problem! Its uncommonness derives from the fact that this version is, actually, solvable efficiently. 


The travelling salesman is on a mission to visit N cities, each exactly once. The cities are represented by numbers 1, 2, ..., N. What we know is the direct flight duration between each pair of cities. The salesman, being the efficient man that he is, wants to modify the city visiting sequence so that the total flight duration is the minimum possible. 

Alas, all is not so simple. In addition, the salesman has a peculiar condition regarding the sequence. For each city labeled K must apply: either all cities with labels smaller than K have been visited before the city labeled K or they will all be visited after the city labeled K. In other words, the situation when one of such cities is visited before, and the other after is not allowed. 

Assist the poor fellow in his ambitious mission and calculate the minimum total flight duration needed in order to travel to all the cities, starting from whichever and ending in whichever city, visiting every city exactly once, so that his peculiar request is fulfilled. 


Input

The first line of input contains the positive integer N (2 ≤ N ≤ 1500), the number of cities. Each of the following N lines contains N positive integers from the interval [0, 1000]. The number in Bth place in the Athrow represents the flight duration between cities A and B; that number is equal to the Ath number in the Bthrow. When A = B, that number is 0. Otherwise, it is a positive value.


Output

The first and only line of output must contain the required minimum total flight duration. 


Example

Input:3 0 5 2 5 0 4 2 4 0 Output:7

Input:
4 0 15 7 8 15 0 16 9 7 16 0 12 8 9 12 0
Output:
31

Clarification of the first example:
the optimal sequence is 2, 1, 3 or 3, 1, 2. The sequence 1, 3, 2 is even more favorable, but it does not fulfill the salesman's condition.

Clarification of the second example:
the sequence is either 3, 1, 2, 4 or 4, 2, 1, 3.


 Submit solution!


题意

旅行商问题TSP大家应该都清知道。这个题目是一个变式的TSP问题。 
经典的TSP问题是指:城市与城市之间有边权,求经过所有城市有且仅有一次,最小边权之和。 
这个题目增加了一个约束条件:对于标号为K的城市,所有标号小于K的城市,要么在K之前被访问,要么都在K之后被访问。 
城市数目2n1500, 从ij的边权cost[i][j][0,1000].


题解:

首先,新加的约束条件其实就是如下表述

先考虑n号点的位置,n号点不是最先到就是最后到。

再考虑n-1号点的位置,在去除n号点的情况下,n-1号点不是最先到就是最后到。

可以进行同样地推理过程,相当于要求出一个序列,从大到小枚举n..1,放在序列的两端。

那么,就是说,假如一共u个城市,若从第u个城市开始,那么有两种情况

1.这个序列的下一个城市是u-1.

2.这个序列的结尾是u-1;


dp[i][j]表示起点为i终点为j的最小访问边权之和。从2n开始枚举顶点。有如下转移方程:(注意i的范围应该不能取到u-1!

dp[u][i]=min{dp[u1][i]+cost[u][u1]}
dp[i][u]=min{dp[i][u1]+cost[u][u1]}}i[1,u1)
dp[u][u1]=min{dp[i][u1]+cost[u][i]}
dp[u1][u]=min{dp[u1][i]+cost[i][u]}}i[1,u1)


 
#include<iostream>#include<cstdio>#include<algorithm>#include<cstring>#include<vector>#include<queue>#include<stack>using namespace std;#define rep(i,a,n) for (int i=a;i<n;i++)#define per(i,a,n) for (int i=n-1;i>=a;i--)#define pb push_back#define fi first#define se secondtypedef vector<int> VI;typedef long long ll;typedef pair<int,int> PII;const int inf=0x3fffffff;const ll mod=1000000007;const int maxn=1500+10;int d[maxn][maxn],cost[maxn][maxn];int main(){    int n;    scanf("%d",&n);    rep(i,1,n+1) rep(j,1,n+1) scanf("%d",&cost[i][j]);    memset(d,0x3f,sizeof(d));    rep(i,1,n+1) d[i][i]=0;    d[1][2]=cost[1][2];    d[2][1]=cost[2][1];    for(int i=2;i<=n;i++)    {        for(int j=1;j<i-1;j++)        {            d[i][j]=min(d[i][j],d[i-1][j]+cost[i][i-1]);            d[j][i]=min(d[j][i],d[j][i-1]+cost[i-1][i]);            d[i][i-1]=min(d[i][i-1],cost[i][j]+d[j][i-1]);            d[i-1][i]=min(d[i-1][i],cost[j][i]+d[i-1][j]);        }    }    int ans=inf;    rep(i,1,n+1) if(i!=n) ans=min(ans,min(d[i][n],d[n][i]));    printf("%d\n",ans);    return 0;}

0 0
原创粉丝点击