HDU 3001(状态压缩dp)
2016-08-12 16:05
423 查看
`这是我第一次写的过了所有的样例,但是WA因为题目是说每个点可以走两次,而我刚开始以为这题就是裸的旅行家问题,后台数据一定专门设置了某个点重复走两次会更小的情况,所以这里需要一种新的方法,三进制!标记
提供几组测试数据:
输入
5 5
2 1 1
3 1 1
4 1 1
5 1 1
2 5 10
答案
14
输入
8 9
2 1 1
3 1 1
4 1 1
5 1 1
2 5 10
4 7 1
4 6 1
4 8 1
8 7 10
答案
27
输入
1 0
答案
0
正确AC代码
提供几组测试数据:
输入
5 5
2 1 1
3 1 1
4 1 1
5 1 1
2 5 10
答案
14
输入
8 9
2 1 1
3 1 1
4 1 1
5 1 1
2 5 10
4 7 1
4 6 1
4 8 1
8 7 10
答案
27
输入
1 0
答案
0
#include <iostream> #include <cstring> #include <cstdio> #include <cmath> #include<algorithm> using namespace std; const int INF = 0x3f3f3f3f; int route[15][15]; int dp[1 << 10][10]; int main() { int n, m; while (~scanf("%d%d", &n, &m)) { memset(route, INF, sizeof(route)); memset(dp, INF, sizeof(dp)); for (int i = 0; i < m; i++) { int a, b; cin >> a >> b; cin >> route[a-1][b-1]; route[b-1][a-1] = route[a-1][b-1]; } for (int i = 0; i < n; i++) { route[i][i] = 0; } int end =( 1 << n ) - 1; for (int i = 0; i < n; i++) { dp[0][i] = 0; } for (int i = 0; i <= end; i++) { for (int j = 0; j < n; j++) { for (int k = 0; k < n; k++) { int temp = 1 << k; if ((temp&i)==0) { int curtemp = i |temp; if (dp[i][j] + route[j][k] < dp[curtemp][k]) { dp[curtemp][k] = dp[i][j] + route[j][k]; } } } } } int Min=INF; for (int i = 0; i < n; i++) { Min = min(Min, dp[end][i]); } if (Min > INF - 100) { cout << -1 << endl; } else { cout << Min << endl; } } return 0; }
正确AC代码
#pragma warning(disable:4996) #include <iostream> #include <cstring> #include <cstdio> #include <cmath> #include<algorithm> using namespace std; const int INF = 0x3f3f3f3f; int State[12];//存储3进制 int visited[60000][12]; int dp[60000][12];//状态为i时以j结尾的最小权值 int map[12][12];//存储图 int n, m; void Initiate() { State[0] = 1; for (int i = 1; i <= 10; i++) State[i] = State[i - 1] * 3;// State {1, 3, 9, 27, 81, 243, 729, 2187, 6561, 19683, 59049, 0}存储3进制每一位对应的数值 for (int i = 0; i <= State[10]; i++)//将 所有不超过59049的数以三进制的形式存储下来, //这样只需要处理一边节省时间,如果是只能访问一边不需要处理因为,电脑本身就是二进制 { int temp = i; for (int j = 0; j <= 10; j++) { visited[i][j] = temp % 3;//每个位置对应的处理号,每个位置i状态对应的访问状况 temp /= 3; } } } int main() { Initiate(); int u, v, w; while (~scanf("%d%d", &n, &m)) { memset(dp, INF, sizeof(dp)); memset(map, INF, sizeof(map)); for (int i = 0; i<n; i++) dp[State[i]][i] = 0; while (m--)//这题比较坑的地方是它输入的时候,两点之间就会输多条边,我们只需要存储最小的就可以了 { scanf("%d%d%d", &u, &v, &w); u--; v--; map[u][v] = map[v][u] = min(map[u][v], w);//无向图两边都要存储 } int Max = INF; for (int i = 0; i<State ; i++)//枚举所有状态 { bool flag = true; for (int j = 0; j<n; j++)//枚举终点 { if (visited[i][j] == 0) flag = false;//是否每个城市都至少走了1次 if (dp[i][j] == INF)//该状态不合法,比如dp[101][1]表示已经访问了2号城市和0号城市 continue; //以1号城市结尾,这样就是不合法的 for (int k = 0; k<n; k++)//枚举没有包括的点 if (j != k) { if (visited[i][k] >= 2)//已经访问了两次 continue; if (map[j][k] == INF)//两点之间不存在回路 continue; dp[i + State[k]][k] = min(dp[i + State[k]][k], dp[i][j] + map[j][k]); //state[k]是已经处理好的类似于二进制中的i|1<<k } } if (flag) { for (int j = 0; j<n; j++) { Max = min(Max, dp[i][j]); } } } if (Max == INF)//无法遍历所有点 Max = -1; cout << Max << endl; } return 0; }
#pragma warning(disable:4996) #include <iostream> #include <cstring> #include <cstdio> #include <cmath> #include<algorithm> using namespace std; const int INF = 0x3f3f3f3f; int state[12]; int visited[80000][15]; int map[15][15]; int dp[80000][15]; void Init() { state[0] = 1; for (int i = 1; i <= 10; i++) { state[i] = state[i - 1] * 3; } for (int i = 0; i < state[10] - 1; i++) { int temp = i; for (int j = 0; j < 10; j++) { visited[i][j] = temp % 3; temp /= 3; } } } int main() { //freopen("in.txt", "r", stdin); Init(); int n, m; while (cin >> n >> m) { memset(dp, INF, sizeof(dp)); memset(map, INF, sizeof(map)); for (int i = 0; i<m; i++) { int start, end; int temp; cin >> start >> end; start--; end--; cin >> temp; map[start][end] = map[end][start] = min(map[start][end], temp); } for (int i = 0; i < n; i++) { map[i][i] = 0; } for (int i = 0; i <n; i++) { dp[0][i] = 0; } for (int i = 0; i <= state - 1; i++) { for (int j = 0; j < n; j++) { for (int k = 0; k < n; k++) if (visited[i][k]<2) { if (dp[i][j] + map[j][k]<= dp[i + state[k]][k]) dp[i + state[k]][k] = dp[i][j] + map[j][k]; } } } int Min = INF; int S = 0; for (int i = 0; i <n; i++) { S += state[i]; } for (int i = S; i <= state - 1; i++) { int flag = 1; for (int j = 0; j < n; j++) { if (visited[i][j] == 0) flag = 0; } if (flag) for (int j = 0; j < n; j++) { Min = min(dp[i][j], Min); } } if (Min == INF) cout << "-1" << endl; else cout << Min << endl; } return 0; }
相关文章推荐
- hdu 3001 dp 状态压缩 3进制
- hdu 3001 3进制状态压缩dp,TSP
- HDU 3001 Travelling(状态压缩DP)
- hdu 3001(状态压缩dp)
- hdu 3001 Travelling (状态压缩dp,三进制!)
- hdu 3001 Travelling(状态压缩dp)
- HDU 3001 Travelling (三进制状态压缩DP+BFS)
- HDU 3001 Travelling (三进制状态压缩 DP)
- HDU 3001 Travelling 【状态压缩DP】
- HDU-3001 Travelling(状态压缩DP,3进制) HQG_AC的博客
- hdu 3001 Travelling (状态压缩dp-----模拟三进制)
- HDU 3001 Travelling(DP状态压缩)
- HDU 3001 Travelling (状态压缩DP)
- HDU 3001 Travelling (三进制状态压缩 DP)
- HDU 3001 Travelling (状态压缩DP +TSP问题)
- HDU 3001【状态压缩DP】
- hdu 3001(状态压缩dp)
- hdu 3001 Travelling//状态压缩DP
- hdu 3001 Travelling 3进制状态压缩dp
- HDU 3001 Travelling(状态压缩dp)