HDU 3001 Travelling(状压dp)

来源:互联网 发布:看门狗画面设置优化 编辑:程序博客网 时间:2024/06/05 04:22

题目链接:【HDU 3001】

acmer想要将n个城市全都走遍,每个城市最多走2遍,输入n个城市,编号为1~n,m条路(a,b,c:a,b表示这条路连通的城市,c表示a,b之间的路费),问acmer'走遍这n个城市最少的时间,要是不能走遍n个城市,那就输出-1

遇到这种路的问题,最好将重边考虑进去,免得出错

因为最多能走两次,所以用3进制的状压dp做

城市最多是10个,状态最多是3^10,先预处理出vis[i][j],表示i状态下j出现的次数

dp[i][j]:i表示已走的城市状态,j表示这个状态下j是最后一个城市

dp[i][j] = min(dp[i][j], dp[tmp][k]+dis[k][j])   ==》 tmp是j这个城市少走一次的状态

每次转移时都要判断j k是否在i状态中

#include <iostream>#include <algorithm>#include <cstdio>#include <cstring>#include <cstring>using namespace std;int n, m, dis[20][20];const int inf=1e9;int vis[60000][15], s[15], dp[60000][15];void init(){for(int i=0; i<=59049; i++){for(int j=1, tmp=i; j<=10; j++, tmp/=3){vis[i][j]=tmp%3;}}s[0]=1;for(int i=1; i<=10; i++) s[i] = s[i-1]*3; }int solve(){int ans=1e9;memset(dp, 0x3f3f3f3f, sizeof(dp));for(int i=1; i<=10; i++) dp[s[i-1]][i]=0;for(int i=0; i<s[n]; i++){int flag=1;for(int j=1; j<=n; j++){if(vis[i][j]==0) {flag=0;continue;}for(int k=1; k<=n; k++){if(vis[i][k]){int tmp = i-s[j-1];dp[i][j] = min(dp[i][j], dp[tmp][k]+dis[k][j]);}}}if(flag){for(int j=1; j<=n; j++){ans = min(ans, dp[i][j]);}}}return ans==1e9 ? -1:ans;}int main(){init();while(~scanf("%d%d", &n, &m)){for(int i=1; i<=n; i++){for(int j=1; j<=n; j++){dis[i][j] = inf;}}for(int i=0; i<m; i++){int a, b, c;scanf("%d%d%d", &a, &b, &c);dis[a][b] = min(dis[a][b], c);dis[b][a] = dis[a][b];}printf("%d\n", solve());}return 0;}


0 0
原创粉丝点击