NOI 题库 4.5之动态规划算法 3368 Sanguo

3368:Sanguo
查看 提交 统计 提问
总时间限制: 3000ms 内存限制: 65536kB
描述
After East Han dynasty, China was divided into several states. Wei, Wu, and Shu are the greatest three states among them. This was the era of Sanguo. During this period, wars frequently happened between states. Zhuge Liang, the commander and strategist of Shu, wanted to enlarge Shu’s power. He was considering conquering N cities. However, these cities must be defeated in a specified order. City-X could be defeated only after City-1, City-2, City-3 … City-(X-1) had been defeated. However, passing through the cities that had not been defeated was eligible. Zhuge wanted to use three generals, Guan Yu, Zhang Fei, and Zhao yun, each of whom should lead an army. The three armies, started from Yizhou, which was numbered with City-0. After conquered all the N cities (each cities must be conquered at least by one army), they had to return to Yizhou.

The N cities and Yizhou were connected by M bi-directed roads. To travel from city to city was a very boring and expensive thing. So Zhuge wanted to minimize the total length of the three armies’ traveling. You were hired to help him to compute the minimum total length of the traveling.

输入
Line1: two integers N and M. N is the number of cities Zhuge wanted to conquer, and M is the number of roads between the N + 1 cities.
Line2…Line(M+1): each line contain 3 integers, X, Y, Len, indicating a road between City-X and City-Y, with the length of Len.
You can suppose that all the N + 1 cities are connected.
N ≤ 500, M ≤ 20000, Len ≤ 1000

输出
Line1: an integer, which is the minimum total length of the three armies’ traveling.
样例输入
5 15
5 5 48
1 4 658
4 0 843
1 4 41
1 4 330
5 2 864
4 2 115
4 0 303
2 3 685
0 0 879
1 5 649
2 4 942
4 0 379
5 2 769
5 1 856
样例输出
3668

题目传送门在这儿

题目大意:给定n个城市之间的距离,注意有可能两个城市之间的最短距离会重复给出,去最小的一个。然后从城市1派出三队人马遍历所有n座城市,问三队人马回到城市1的所有行程距离之和最小是多少?
算法策略:重要的想出子问题的描述方式,受到 Tour这道题的启发,可以写出dp(i,j,k)表示三队人马分别在i,j,k城市而且i之前的城市都已经被遍历过了,要求i>j>k,在动归的过程中可以做到这一点。那么容易写出递推方程:dp(i+1,j,k)=dp(i,j,k)+dist(i,i+1),
dp(i+1,i,k)=dp(i,j,k)+dist(j,i+1),
dp(i+1,j,i)=dp(i,j,k)+dist(k,i+1)
其中的dist(i,j)可以用迪杰斯特拉算法算出两点之间的最小距离。
最后的结果就是dp(n,i,j)+dist(1,n)+dist(i,1)+dist(j,1)的最小值。
注意这一题还需要用滚动数组,不然空间也会被限制。

代码如下:

#include<iostream>
#include<cstring>
using namespace std;
long long dp[2][501][501]={};
long long dist[501][501]={};
int main(){
int n,m;
while(cin>>n>>m){
for(int i=0;i<=n;++i)
for(int j=0;j<=n;++j){
dist[i][j]=30000000;
dp[0][i][j]=30000000;
dp[1][i][j]=30000000;
}
dp[0][0][0]=0;
for(int i=0;i<=n;++i)
dist[i][i]=0;
for(int i=0;i<m;++i){
long long x,y,len;
cin>>x>>y>>len;
dist[x][y]=min(dist[x][y],len);
dist[y][x]=min(dist[x][y],dist[y][x]);
dist[x][y]=dist[y][x];
}
for(int k=0;k<=n;++k)
for(int i=0;i<=n;++i)
for(int j=0;j<=n;++j)
dist[i][j]=min(dist[i][j],dist[i][k]+dist[k][j]);
for(int i=0;i<n;++i){
for(int j=0;j<=i;++j)
for(int k=j;k<=i;++k){
dp[(i+1)%2][j][k]=min(dp[(i+1)%2][j][k],dp[i%2][j][k]+dist[i+1][i]);
dp[(i+1)%2][k][i]=min(dp[(i+1)%2][k][i],dp[i%2][j][k]+dist[j][i+1]);
dp[(i+1)%2][j][i]=min(dp[(i+1)%2][j][i],dp[i%2][j][k]+dist[k][i+1]);
}
memset(dp[i%2],0x6f,sizeof(dp[i%2]));
}
long long result=1<<30;
for(int i=0;i<=n;++i)
for(int j=i;j<=n;++j){
result=min(result,dp[n%2][i][j]+dist[i][0]+dist[j][0]+dist[n][0]);
}
cout<<result<<endl;
}
}

时间复杂度:O(n^3)

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值