这题是hdu 4114...
跟着19的打了打周测,发现个好题
写了写还wa了一发
题目大意:
给出n个点,k个要旅游的景点,然后给出k个景点的信息(位置,t,ft,门票所在地点),t于ft表示,如果参观这个经典使用门票则需要ft时间,否则需要t时间。问参观完所有经典并且返回来的最短路。
题目思路:
经典套路状压dp了,类似于状压dp求哈密尔顿回路
由于涉及到两个状态,所以设状态:i,k分别为门票的状态二进制 与 访问状态的二进制
然后就直接进行状压dp就好了,注意的是最短路最好提前处理好,点数比较小Floyd就好了
Code:
#include<bits/stdc++.h>
#pragma GCC optimize("Ofast")
#pragma GCC optimize("inline")
#pragma GCC optimize("-fgcse")
#pragma GCC optimize("-fgcse-lm")
#pragma GCC optimize("-fipa-sra")
#pragma GCC optimize("-ftree-pre")
#pragma GCC optimize("-ftree-vrp")
#pragma GCC optimize("-fpeephole2")
#pragma GCC optimize("-ffast-math")
#pragma GCC optimize("-fsched-spec")
#pragma GCC optimize("unroll-loops")
#pragma GCC optimize("-falign-jumps")
#pragma GCC optimize("-falign-loops")
#pragma GCC optimize("-falign-labels")
#pragma GCC optimize("-fdevirtualize")
#pragma GCC optimize("-fcaller-saves")
#pragma GCC optimize("-fcrossjumping")
#pragma GCC optimize("-fthread-jumps")
#pragma GCC optimize("-funroll-loops")
#pragma GCC optimize("-freorder-blocks")
#pragma GCC optimize("-fschedule-insns")
#pragma GCC optimize("inline-functions")
#pragma GCC optimize("-ftree-tail-merge")
#pragma GCC optimize("-fschedule-insns2")
#pragma GCC optimize("-fstrict-aliasing")
#pragma GCC optimize("-falign-functions")
#pragma GCC optimize("-fcse-follow-jumps")
#pragma GCC optimize("-fsched-interblock")
#pragma GCC optimize("-fpartial-inlining")
#pragma GCC optimize("no-stack-protector")
#pragma GCC optimize("-freorder-functions")
#pragma GCC optimize("-findirect-inlining")
#pragma GCC optimize("-fhoist-adjacent-loads")
#pragma GCC optimize("-frerun-cse-after-loop")
#pragma GCC optimize("inline-small-functions")
#pragma GCC optimize("-finline-small-functions")
#pragma GCC optimize("-ftree-switch-conversion")
#pragma GCC optimize("-foptimize-sibling-calls")
#pragma GCC optimize("-fexpensive-optimizations")
#pragma GCC optimize("inline-functions-called-once")
#pragma GCC optimize("-fdelete-null-pointer-checks")
using namespace std;
const int N=1e3+15;
typedef long long ll;
const ll INF = 1e18;
double PI=acos(-1.0);
inline bool read(ll &num)
{char in;bool IsN=false;
in=getchar();if(in==EOF) return false;while(in!='-'&&(in<'0'||in>'9')) in=getchar();if(in=='-'){ IsN=true;num=0;}else num=in-'0';while(in=getchar(),in>='0'&&in<='9'){num*=10,num+=in-'0';}if(IsN) num=-num;return true;}
const int maxn=1e6+5;
ll n,m,p;
ll mp[55][55];
ll dp[55][1<<8][1<<8];
ll f[55];
int pos[55],ft[55],t[55];
void _inint(){
for(int i=0;i<55;i++){
for(int k=0;k<55;k++){
if(i==k) mp[i][k] = 0;
else mp[i][k] = INF;
}
}
for(int i=0;i<55;i++){
for(int k=0;k<1<<8;k++){///游览状态
for(int j=0;j<1<<8;j++){
dp[i][k][j] = INF;
}
}
}
memset(f,0,sizeof(f));
dp[1][0][0] = 0;///初始状态
}
int main()
{
int cas = 0;
int T;scanf("%d",&T);
while(T--){
_inint();
read(n);read(m);read(p);
for(int i=1;i<=m;i++){
ll x,y,w;read(x);read(y);read(w);
mp[x][y] = min(mp[x][y],w);
mp[y][x] = min(mp[y][x],w);
}
for(int i=1;i<=n;i++)
for(int k=1;k<=n;k++)
for(int j=1;j<=n;j++)
mp[k][j] = min(mp[k][i]+mp[i][j],mp[k][j]);
for(int i=0;i<p;i++){
int x;
scanf("%d%d%d%d",&pos[i],&t[i],&ft[i],&x);
while(x--){
ll y;read(y);
f[y] |= 1<<i;
}
}
ll ans = INF;
for(int i=0;i<(1<<p);i++){///访问景点
for(int k=0;k<(1<<p);k++){///门票
for(int j=1;j<=n;j++){
if(dp[j][i][k] != INF){
if(i == ((1<<p)-1)) ans = min(ans,dp[j][i][k]+mp[j][1]);
for(int aim=0;aim<p;aim++){
if((i&(1<<aim)) == 0){///没去过
if(k&(1<<aim)) ///有门票
dp[pos[aim]][i^(1<<aim)][k|f[pos[aim]]] = min(dp[pos[aim]][i^(1<<aim)][k|f[pos[aim]]],dp[j][i][k]+mp[j][pos[aim]]+ft[aim]);
else dp[pos[aim]][i^(1<<aim)][k|f[pos[aim]]] =min(dp[pos[aim]][i^(1<<aim)][k|f[pos[aim]]],dp[j][i][k]+mp[j][pos[aim]]+t[aim]);
}
}
///不去游玩 到处跑
for(int aim=1;aim<=n;aim++){
dp[aim][i][k|f[aim]] = min(dp[aim][i][k|f[aim]],dp[j][i][k]+mp[aim][j]);
}
}
}
}
}
printf("Case #%d: %lld\n",++cas,ans);
}
return 0;
}