http://endlesscount.blog.163.com/blog/static/821197872012525113427573/
poj3123 这个只有30个节点, 直接floyd即可, 后面找最优解还是比较恶心的, 不过一共就2^4个状态,再 循环4次搞定, 老外还有一种神代码, 看了好久才懂
不过最后看了别人的代码, 还有一种合并的方法
#include <cstdio>
#include <map>
#include <string>
#include <iostream>
#include <cstring>
#define lowbit(x) ((x)&(-x))
using namespace std;
const int maxn=50;
const int inf=0x3f3f3f3f;
map<string, int>cityid;
int dist[maxn][maxn];
int dp[300][maxn];
const int sta[]={0, 3, 12, 48, 192, 15, 51, 195, 60, 204, 240, 63, 207, 243, 252, 255};
int bit(int x)
{
x=lowbit(x);
int res=0;
for (; x; x>>=1, res++);
return res-1;
}
int main()
{
int n, m;
while(cin >> n >> m, n||m)
{
string a, b;
int cnt, limit=256;
memset (dist, 0x3f, sizeof(dist));
cityid.clear();
for (int i=0; i<n; ++i)
{
cin >> a;
cityid[a]=i;
dist[i][i]=0;
}
for (int i=0; i<m; ++i)
{
cin >> a >> b >> cnt;
int fa=cityid[a], fb=cityid[b];
dist[fb][fa]=dist[fa][fb]=min(dist[fa][fb], cnt);
}
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]);
memset (dp, 0x3f, sizeof(dp));
int info[10];
for (int i=0; i<8; ++i)
{
cin >> a;
info[i]=cityid[a];
for (int j=0; j<n; ++j)
{
dp[1<<i][j]=dist[cityid[a]][j];
}
}
for (int j=0; j<limit; ++j)
{
int c=0;
if(j&(j-1)==0)continue;
/// o(n*n*2^k) 没仔细估。
for (int i=0; i<n; ++i)
{
for (int sub=j; sub; sub=(sub-1)&j)
{/// 用压缩的子状态推出当前状态,这时并不是最优解, 会有些边被重复计算。
dp[j][i]=min(dp[j][i], dp[sub][i]+dp[j-sub][i]);
}
if(dp[j][i]<dp[j][c])c=i;
}
/// O(n*n*2^k)
for (int i=0; i<n; ++i)
for (int k=0; k<n; ++k)
{///同状态用最小的状态去更新, 这时便会对有重复的边进行去重。
dp[j][k]=min(dp[j][k], dp[j][i]+dist[i][k]);
}
}
int ans=inf;
for (int p1=0; p1<16; ++p1)
{
for (int p2=0; p2<16; ++p2)
{
for (int p3=0; p3<16; ++p3)
{
for (int p4=0; p4<16; ++p4)
{
if(sta[p1]+sta[p2]+sta[p3]+sta[p4]==255)
{
for (int i=0; i<n; ++i)
{
int tmp=0;
if(sta[p1]!=0)tmp+=dp[sta[p1]][info[bit(sta[p1])]];
if(sta[p2]!=0)tmp+=dp[sta[p2]][info[bit(sta[p2])]];
if(sta[p3]!=0)tmp+=dp[sta[p3]][info[bit(sta[p3])]];
if(sta[p4]!=0)tmp+=dp[sta[p4]][info[bit(sta[p4])]];
ans=min(tmp, ans);
}
}
}
}
}
}
cout << ans << endl;
//cout << dp[243][4] << endl;
//cout << dp[12][2] << endl;
}
return 0;
}
/*
6 6
1 2 3 4 5 6
1 2 1
2 3 1
3 4 1
4 6 1
6 5 1
1 5 1
5 6
2 3
5 6
6 4
*/
hdu 4085 3次dp 算上floyd的话 4次了
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=55;
const int inf=0x3f3f3f3f;
int N, M, K;
int dist[maxn][maxn];
int dp[1234][maxn];
bool check(int x)
{
///int mask1=x&((1<<K)-1), mask2=x&((1<<(K*2))-(1<<K));
int cnt1=0, cnt2=0;
for (int i=0; i<K; ++i)
{
if(x&(1<<i))cnt1++;
if(x&(1<<i+K))cnt2++;
}
//printf("%d %d %d\n", x, cnt1, cnt2);
return cnt1==cnt2;
}
int main()
{
int cas; scanf("%d", &cas);
while (cas--)
{
scanf("%d%d%d", &N, &M, &K);
memset (dist, 0x3f, sizeof(dist));
for (int i=0; i<M; ++i)
{
int a, b, c; scanf("%d%d%d", &a, &b, &c);
a--, b--;
dist[a][b]=dist[b][a]=min(dist[a][b], c);
}
for (int i=0; i<N; ++i)dist[i][i]=0;
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][k]+dist[k][j], dist[i][j]);
int limit=1<<(K<<1);
memset (dp, 0x3f, sizeof(dp));
for (int i=0; i<K; ++i)
{
for (int j=0; j<N; ++j)
{
dp[1<<i][j]=dist[i][j];
dp[1<<(i+K)][j]=dist[N-K+i][j];
}
}
for (int i=0; i<limit; ++i)///if(i&(i-1))
{
for (int j=0; j<N; ++j)
{
for (int sub=i&(i-1); sub; sub=(sub-1)&i)
{
dp[i][j]=min(dp[i][j], dp[i^sub][j]+dp[sub][j]);
}
}
for (int j=0; j<N; ++j)
{
for (int k=0; k<N; ++k)
{
dp[i][j]=min(dp[i][j], dp[i][k]+dist[k][j]);
}
}
}
int d[1234];
memset (d, 0x3f, sizeof(d));
for (int i=0; i<limit; ++i)
if(check(i))
for (int j=0; j<N; ++j)
d[i]=min(d[i], dp[i][j]);
for (int i=0; i<limit; ++i)
{
if(check(i))
{
for (int j=0; j<limit; ++j)
{
if(check(j))
if((i|j)==i && (i&j)!=i)
{
d[i]=min(d[i], d[j]+d[j^i]);
}
}
}
}
// int ans=0x3f3f3f3f;
// for (int i=0; i<N; ++i)
// {
// ans=min(ans, dp[limit-1][i]);
// }
if(d[limit-1]==inf)puts("No solution");
else printf("%d\n", d[limit-1]);
}
return 0;
}
/*
10
4 3 2
1 2 3
2 3 4
3 4 5
4 3 1
4 2 10
3 1 9
2 3 10
6 2 2
1 5 1000
2 6 1000
6 2 2
1 5 1000
2 5 1000
*/
zju 3613Wormhole Transport
同一个算法 就是判断变一下而已
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int inf=0x3f3f3f3f;
const int maxn=222;
int N;
int dist[maxn][maxn];
int dp[1<<10][maxn];
int ans[1<<10];
bool check(int a, int pre)
{
int cnt1=0, cnt2=0;
for (int i=0; a; a>>=1, ++i)
{
if(a&1)
{
if(i<pre)cnt1++;
else cnt2++;
}
}
return cnt1==cnt2;
}
int main()
{
while (~scanf("%d", &N))
{
int fac[16], rsc[16];
int cnt1=0, cnt2=0;
memset (dist, 0x3f, sizeof(dist));
int pro=0;
for (int i=0; i<N; ++i)
{
int p, s; scanf("%d%d", &p, &s);
///if(s==1 && p>=1)s-=1, p-=1, pro+=1;
while (p--)fac[cnt1++]=i;
while (s--)rsc[cnt2++]=i;
dist[i][i]=0;
}
int m; scanf("%d", &m);
for (int i=0; i<m; ++i)
{
int a, b, c; scanf("%d%d%d", &a, &b, &c);
a--, b--;
dist[a][b]=dist[b][a]=min(dist[a][b], c);
}
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<cnt2; ++i)
{
fac[cnt1+i]=rsc[i];
}
memset (dp, 0x3f, sizeof(dp));
for (int i=0; i<cnt2+cnt1; ++i)
{
for (int j=0; j<N; ++j)
{
dp[1<<i][j]=dist[fac[i]][j];
}
}
int limit=1<<(cnt1+cnt2);
for (int i=0; i<limit; ++i)
{
for (int j=0; j<N; ++j)
{
for (int sub=(i-1)&i; sub; sub=(sub-1)&i)
{
dp[i][j]=min(dp[i][j], dp[sub][j]+dp[sub^i][j]);
}
}
for (int j=0; j<N; ++j)
for (int k=0; k<N; ++k)
dp[i][j]=min(dp[i][j], dp[i][k]+dist[k][j]);
}
//for (int i=0; i<limit; ++i)
memset (ans, 0x3f, sizeof(ans));
for (int i=0; i<limit; ++i)if(check(i, cnt1))
for (int j=0; j<N; ++j)
ans[i]=min(dp[i][j], ans[i]);
for (int i=0; i<limit; ++i)if(check(i, cnt1))
{
for (int sub=(i-1)&i; sub; sub=(sub-1)&i)if(check(sub, cnt1))
{
ans[i]=min(ans[i], ans[sub]+ans[sub^i]);
}
}
int cost=0;
for (int i=0; i<limit; ++i)if(check(i, cnt1))if(ans[i]!=inf)
{
int tmp=0;
for (int j=0; j<cnt1; ++j)if((1<<j)&i)tmp++;
//printf("%d %d %d\n", i, tmp, ans[i]);
if(pro<tmp)
{
pro=tmp;
cost=ans[i];
}
if(pro==tmp)cost=min(cost, ans[i]);
}
printf("%d %d\n", pro, cost);
}
return 0;
}
/*
2
1 0
0 1
1
1 2 3
3
1 1
1 1
1 1
2
1 2 3
2 3 1
*/