題意:某人舉辦了一個party,邀請了他的朋友來,他的朋友也邀請了他們的朋友.etc。然後某人並不認識他朋友的朋友,這樣聊天很尬,所以就讓邀請他不認識的人的朋友給某人介紹。假設通過朋友C介紹的話,那麼朋友C的所有朋友都會成爲朋友,問讓所有人成爲朋友需要幾個人來介紹,輸出他們。
題解:
因爲最多隻有22個人,所以比較容易想起用狀態壓縮,然後BFS枚舉每一個人做第一個介紹的情況就好了。
具體看代碼註釋吧。
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
const int maxn = (1 << 22) + 10;
int dp[maxn],last[maxn],opt[maxn],val[maxn],ans[25],n,m;//last是記錄上一個數是多少,opt是記錄標號
void bfs()
{
memset(opt,-1,sizeof opt);
memset(last,-1,sizeof last);
queue<int> q;
while(!q.empty())q.pop();
for (int i = 0; i < n; i++)
{
dp[val[i]] = 1;
opt[val[i]] = i;//標號賦值
q.push(val[i]);
}
while(!q.empty())
{
int now = q.front();
q.pop();
for (int i = 0; i < n; i++)
{
if(now & (1<<i))//當前的數的第i位是1,也就是朋友i可以做介紹
{
int tmp = now|val[i];
if(dp[tmp] == 0)//出現的是沒有記錄過的數
{
dp[tmp] = dp[now] + 1;//更新dp
opt[tmp] = i;//記錄更新到tmp的狀態是通過i做介紹得來的
last[tmp] = now;//記錄tmp的是now通過i做介紹得來的,用來記錄路徑。
q.push(tmp);
if(tmp == (1 << n) - 1)
return;
}
}
}
}
}
int main()
{
while(~scanf("%d %d",&n,&m))
{
memset(dp,0,sizeof dp);
memset(val,0,sizeof val);
for (int i = 0; i < n; i++)
val[i] |= 1 << i;
for (int i = 0; i < m; i++)
{
int a,b;
scanf("%d %d",&a,&b);
a--,b--;//因爲上面給數的某一位賦1需要從0開始,所以下標全部-1
val[a] |= 1 << b;
val[b] |= 1 << a;
}
if(m == n * (n - 1) / 2)
{
printf("0\n");
continue;
}
bfs();
int tmp = (1 << n) - 1,mount = 0;
while(tmp != -1)
{
ans[mount++] = opt[tmp];
tmp = last[tmp];
}
printf("%d\n",mount);
for (int i = mount - 1; i > 0; i--)
{
printf("%d ",ans[i] + 1);//下標再加回來
}
printf("%d\n",ans[0] + 1);
}
}