• HAOI2017 新型城市化


    题目链接:戳我

    我们把有贸易关系的城市连起来,题目中就是要求连上哪些边,这张图里面的最大团会至少+1。

    题目中告诉我们这个图里面团的个数最多有两个,那么就是说它的反图,是一个二分图(因为团如果有1个的话,显然反图中所有点都彼此独立,是一个二分图。团如果有两个的话,不在一个团的点一定在两边,而因为只有两个团,所以肯定是能成为二分图)

    因为原图的团==反图的最大独立集,那么问题就可以转化成,在它的反图里,删去哪一条边,可以使得最大独立集至少+1

    然后因为二分图最大独立集==二分图最大匹配,所以我们可以直接跑一个dinic。

    然后在残量网络上跑SCC缩点,如果一条边满流,且左右端点不在一个SCC里面,那么它就一定在二分图最大匹配里面

    所以我们就会做了。先黑白染色连成二分图,然后跑dinic,然后再缩点,然后再判断一下就行了。

    代码如下:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #include<queue>
    #include<vector>
    #define S 0
    #define T n+1
    #define MAXN 100010
    #define INF 0x3f3f3f3f
    using namespace std;
    int n,m,tot,t,tt=1,top,cnt;
    int id[MAXN],head[MAXN];
    int low[MAXN],dfn[MAXN],st[MAXN],in[MAXN],c[MAXN],cur[MAXN],dis[MAXN];
    struct Edge{int nxt,to,dis;}edge[MAXN<<1];
    struct Line{int u,v,w;}line[MAXN<<1];
    struct Node{int u,v;};
    vector<int>pre[MAXN];
    vector<Node>ans;
    inline bool cmp(struct Node x,struct Node y)
    {
        if(x.u==y.u) return x.v<y.v;
        return x.u<y.u;
    }
    inline void add(int from,int to,int dis)
    {
        edge[++tt].nxt=head[from],edge[tt].to=to,edge[tt].dis=dis,head[from]=tt;
        edge[++tt].nxt=head[to],edge[tt].to=from,edge[tt].dis=0,head[to]=tt;
    }
    inline bool bfs()
    {
        memset(dis,0x3f,sizeof(dis));
        memcpy(cur,head,sizeof(head));
        queue<int>q;
        q.push(S);
        dis[S]=0;
        while(!q.empty())
        {
            int u=q.front();q.pop();
            for(int i=head[u];i;i=edge[i].nxt)
            {
                int v=edge[i].to;
                if(dis[v]==0x3f3f3f3f&&edge[i].dis)
                {
                    dis[v]=dis[u]+1;
                    q.push(v);
                }
            }
        }
        if(dis[T]==0x3f3f3f3f) return false;
        return true;
    }
    inline int dfs(int x,int f)
    {
        if(x==T||!f) return f;
        int used=0,w;
        for(int i=cur[x];i;i=edge[i].nxt)
        {
            cur[x]=i;
            if(dis[edge[i].to]==dis[x]+1&&(w=dfs(edge[i].to,min(f,edge[i].dis))))
            {
                used+=w,f-=w;
                edge[i].dis-=w,edge[i^1].dis+=w;
                if(!f) break;
            }
        }
        return used;
    }
    inline int dinic()
    {
        int cur_ans=0;
        while(bfs()) cur_ans+=dfs(S,0x3f3f3f3f);
        return cur_ans;
    }
    inline void tarjan(int x)
    {
        low[x]=dfn[x]=++tot;
        in[x]=1,st[++top]=x;
        for(int i=head[x];i;i=edge[i].nxt)
        {
            int v=edge[i].to;
            if(edge[i].dis==0) continue;
            if(!dfn[v]) tarjan(v),low[x]=min(low[x],low[v]);
            else if(in[v]) low[x]=min(low[x],dfn[v]);
        }
        if(dfn[x]==low[x])
        {
            int v;cnt++;
            do{v=st[top--];in[v]=0;c[v]=cnt;}while(v!=x);
        }
    }
    inline void solve(int x,int op)
    {
        id[x]=op;
        for(int i=0;i<pre[x].size();i++)
            if(!id[pre[x][i]])
                solve(pre[x][i],3-op);
    }
    int main()
    {
        #ifndef ONLINE_JUDGE
        freopen("ce.in","r",stdin);
        #endif
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d",&line[i].u,&line[i].v);
            pre[line[i].u].push_back(line[i].v);
            pre[line[i].v].push_back(line[i].u);
        }
        for(int i=1;i<=n;i++)
            if(!id[i])
                solve(i,2);
        for(int i=1;i<=n;i++)
        {
            if(id[i]==2) 
            {
                add(S,i,1);//printf("[%d %d]
    ",S,i,1);
                for(int j=0;j<pre[i].size();j++)
                    add(i,pre[i][j],1);//printf("[%d %d]
    ",i,edge[j].to);
            }
            else add(i,T,1);//printf("[%d %d]
    ",i,T);
        }
        // cout<<dinic()<<endl;
        dinic();
        for(int i=1;i<=n;i++)
            if(!dfn[i])
                tarjan(i);
        for(int i=1;i<=n;i++)
            if(id[i]==2)
                for(int j=head[i];j;j=edge[j].nxt)
                {
                    int v=edge[j].to;
                    if(edge[j].dis||v==S||v==T) continue;
                    if(c[i]!=c[v])
                    {
                        if(i<v) ans.push_back((Node){i,v});
                        else ans.push_back((Node){v,i});
                    }
                }
        sort(ans.begin(),ans.end(),cmp);
        printf("%d
    ",ans.size());
        for(int i=0;i<ans.size();i++)
            printf("%d %d
    ",ans[i].u,ans[i].v);
        return 0;
    }
    
  • 相关阅读:
    KindEditor粘贴word图片且图片文件自动上传功能
    umeditor粘贴word图片且图片文件自动上传功能
    百度Web编辑器粘贴word图片且图片文件自动上传功能
    PHP大文件上传支持断点上传解决方案
    PHP大文件上传支持断点上传教程
    matlab函数——shading函数
    Matlab griddata函数功能介绍
    戴尔 SE2416HM
    visio中如何旋转形状
    axios的封装与异常处理(async/await)
  • 原文地址:https://www.cnblogs.com/fengxunling/p/10811217.html
Copyright © 2020-2023  润新知