先上題目:ide
input | output |
---|---|
3 3 3 0 2 0 0 2 1 1 2 2 |
2 0 2
|
題意:給出n個點m條邊(無向),有k種駕照,每條邊若是想經過的話須要某一種駕照,問你從0號點到1號點最少須要多少種駕照,並把它們輸出。this
作法:狀態壓縮而後暴力檢查是否合法,記錄最少須要多少中駕照。spa
s[i][j]表示從i->j的話有哪幾種能夠用的駕照。而後枚舉不一樣的駕照組合,找到最少須要的數目之後輸出便可。ssr
上代碼:code
1 #include <cstdio> 2 #include <cstring> 3 #include <utility> 4 #include <set> 5 #define MAX 32 6 #define MK(x,y) (make_pair(x,y)) 7 using namespace std; 8 9 int s[MAX][MAX]; 10 bool vis[MAX]; 11 int k,n,m; 12 13 bool dfs(int u,int caps) { 14 vis[u]=1; 15 if(u==1) return 1; 16 for(int i=0;i<n;i++){ 17 if(!vis[i] && (caps&s[u][i])){ 18 if(dfs(i,caps)) return 1; 19 } 20 } 21 return 0; 22 } 23 24 int main() { 25 int u,v,cap,ans,caps,f; 26 //freopen("data.txt","r",stdin); 27 while(scanf("%d %d %d",&k,&n,&m)!=EOF) { 28 memset(s,0,sizeof(s)); 29 for(int i=0;i<m;i++){ 30 scanf("%d %d %d",&u,&v,&cap); 31 if(u==v) continue; 32 s[u][v]|=(1<<cap); 33 s[v][u]|=(1<<cap); 34 } 35 ans=k+1; 36 caps=0; 37 for(int i=1;i<(1<<k);i++){ 38 int cnt=0; 39 for(int j=0;j<k;j++){ 40 if(i&(1<<j)) cnt++; 41 } 42 if(cnt>=ans) continue; 43 memset(vis,0,sizeof(vis)); 44 if(dfs(0,i)){ 45 ans=cnt; 46 caps=i; 47 } 48 } 49 printf("%d\n",ans); 50 f=0; 51 for(int i=0;caps>0;caps>>=1,i++){ 52 if(caps&1){ 53 if(f++) printf(" "); 54 printf("%d",i); 55 } 56 } 57 printf("\n"); 58 } 59 return 0; 60 }