CodeForces 906C(狀態壓縮 +BFS)

題目鏈接

題意:某人舉辦了一個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);

    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章