题意:
有n个十字路口(就是路的端点啦)、m条路、k中驾照,每一条路可属于若干种驾照(拥有
相应的驾照才能在这条路上通行)
求从编号为0的十字路口走到编号为1的十字路口,最少要有多少种驾照。
因为驾照数很少,可以用位来模拟相应的驾照。
然后枚举得到既能从0到1又最少的需求。
e[i][j]中为1的位代表这条路属于该驾照。
照着小伙伴的思路自己敲了一遍。。。。感觉结合位运算的搜索真是太神奇了!!!
#include<cstdio>
#include<cstring>
#include<iostream>
#define INF 0x3f3f3f3f
using namespace std;
int k,license[25],n;
int vis[35];
int e[35][35];
void dfs(int s,int now)
{
vis[s]=1;
if(s==1) return;
for(int i=0;i<n;i++)
{
if((e[s][i]&now) && !vis[i])
dfs(i,now);
}
}
int main()
{
int m,v1,v2,c,tmp,now,ans,cato,cnt;
while(scanf("%d%d%d",&k,&n,&m)!=EOF)
{
memset(e,0,sizeof(e));
for(int i=0;i<m;i++)
{
scanf("%d%d%d",&v1,&v2,&c);
e[v1][v2]=(e[v1][v2]|(1<<c));
e[v2][v1]=e[v1][v2];
}
ans=INF;
int i;
for(i=0;i<(1<<k);i++)
{
tmp=i;
cnt=0;
while(tmp) //剪枝。大于已经求得的
{ //符合要求所需的驾照数就不必再dfs了
if(tmp&1)
cnt++;
tmp=tmp>>1;
}
if(cnt>=ans) continue;
memset(vis,0,sizeof(vis));
now=i;
dfs(0,now);
if(vis[1]) //如果能够到1
{
ans=0,cato=0;
while(now)
{
if(now&1)
{
license[ans++]=cato;
}
now>>=1;
cato++; //驾照的种类编号
}
}
}
printf("%d\n",ans);
for(int i=0;i<ans-1;i++)
printf("%d ",license[i]);
printf("%d\n",license[ans-1]);
}
return 0;
}