P1330 封锁阳光大学

原题链接  https://www.luogu.com.cn/problem/P1330

 

 

 

 

思路

这题思路应该挺多,我经过思索后,感觉可以染色。

如果一条边的一端有河蟹,那么另一端必然没有;而如果一端没有河蟹,那么另一端一定有。所以,遍历每条边(至少一端已经染色),如果另一端没有染色,则染上和这一端相反的颜色;如果都已经染色,判断是否相反,是就不管,不是就一定 $Impossible$ 

由于要按边遍历,数据范围又超大,只能用邻接表,具体见代码。

再说广搜。需要每染色一个点就把此点放进队列,并标记。我选择广搜的原因是不用递归,发现不满足就可以直接返回。

细节

这道题其实细节挺多。

首先,为了方便遍历,建边时要建双向边。

其次,原图并非连通图,所以应该每个点都搜一次(搜过就不搜了),即在主函数上加一层循环。

如果可以满足,就要统计河蟹最小个数,也就是在每次广搜都统计一遍,再加起来。其实每次的个数就是两种颜色用的少的的个数,注意在每次搜完后都要求值。

$Code$:

#include<cstdio>
#include<algorithm>
#include<queue>
using namespace std;
const int MAXN=10010,MAXM=200010;
int n,m,tot=0,sum[3],ans=0;
int h[MAXN],vis[MAXN];
struct node
{
    int v;
    int next;
}e[MAXM];
void add(int u,int v)
{
    tot++;
    e[tot].v=v;
    e[tot].next=h[u];h[u]=tot;
}
queue<int> q;
bool bfs(int start)
{
    vis[start]=1;
    sum[1]=1,sum[2]=0;
    q.push(start);
    while(!q.empty())
    {
        int u=q.front();q.pop();
        for(int k=h[u];k;k=e[k].next)
        {
            int v=e[k].v;
            if(vis[v]==vis[u]) return 1;
            if(vis[v]==0)
            {
                vis[v]=vis[u]%2+1;
                sum[vis[v]]++;
                q.push(v);
            }
        }
    }
    return 0;
}
int main()
{
    scanf("%d%d",&n,&m);
    while(m--)
    {
        int u,v;
        scanf("%d%d",&u,&v);
        add(u,v);
        add(v,u);
    }
    for(int i=1;i<=n;i++)
    {
        if(vis[i]) continue;
        if(bfs(i))
        {
            printf("Impossible");
            return 0;
        }
        else ans+=min(sum[1],sum[2]);
    }
    printf("%d",ans);
    return 0;
}

 

posted @ 2020-04-25 21:07  暗い之殇  阅读(150)  评论(0编辑  收藏  举报