动态规划训练之八

哎,题型真的变化无穷啊

先考虑如果每个点只能走一次,那么这就是个典型的状压dp的裸题

但这时候每个点可以最多走两次,怎么办?

当每个点只能走两次的时候,

我们用二进制的的0表示该点没有被选到,1表示该点被选到

这时候我们就可以用三进制的2表示该点被经过了两次

code(写的很清晰,就是顶格写了,不是很好看):

#include <iostream>
#include <string>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <ctime>
#include <queue>
#include <stack>
#include <list>
#include <algorithm>

using namespace std;

int pat[12] = {0,1,3,9,27,81,243,729,2187,6561,19683,59049};
int n,m;
int edge[11][11];
int idx[59049][11] = {0};
int dp[59049][11];

void initidx()
{
for(int i = 0 ; i < 59049 ; ++i)
{
int temp = i ; 
for(int j = 1 ; j <= 10 ; ++j)
{
idx[i][j] = temp%3;
temp /= 3;
if(temp == 0)break;
}
}
}


int main()
{
initidx();
while(~scanf("%d%d",&n,&m))
{
memset(edge , 0x3f , sizeof(edge));
memset(dp , 0x3f , sizeof(dp));
for(int i = 0 ; i < m ; ++i)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
if(edge[a][b] > c)
edge[a][b] = edge[b][a] = c;
}
for(int i = 1 ; i <= n ; ++i)
dp[pat[i]][i] = 0;
int ans = 0x3f3f3f3f;
for(int i = 0 ; i < pat[n+1] ; ++i)
{
int complete = 1;
for(int j = 1 ; j <= n ; ++j)
{
if(idx[i][j] == 0) complete = 0;
if(dp[i][j] == 0x3f3f3f3f) continue;
for(int k = 1 ; k <= n ; ++k)
{
if(j == k || edge[k][j] == 0x3f3f3f3f || idx[i][k] >= 2)continue;
int temp = i + pat[k];
dp[temp][k] = min(dp[temp][k] , dp[i][j] + edge[j][k]);
}
}
if(complete)
    for(int j = 1 ; j <= n ; ++j)  
                ans = min(ans,dp[i][j]);
}
if(ans == 0x3f3f3f3f)
{
puts("-1");  
continue;  
}
 
printf("%d\n",ans);  
}
return 0;
}
posted @ 2019-10-09 10:20  wzx_believer  阅读(90)  评论(0编辑  收藏  举报