ASFNU SC Day1

暑期训练的第一天,学习图论。

包括强/双连通分量,割点与桥,二分图,2-Sat等。

----算法模板---

坑放这,以后再填。

------例题-------

坑放这,以后再填。

-----模拟赛-----

地址:https://cn.vjudge.net/contest/235355

A.矿场搭建

  (为方便,本题把两个用无向边连接的点和单点也叫做点双连通子图)

  1.单个的点双(点双中无割点):

    只有两种情况,一是只有一个点,二是有两个点以上的。

    对于第一种,在它上面放一个点就好了。

    对于第二种,在它上面随意放两个点就行。

  2.多个的点双(点双中有割点):

    显然点双之间会有公共点割点。

    只要保证割点两侧有一个出口就好。

    对于有两个割点的点双,在它们上面放点没有意义。

    对于只有一个割点的点双,在它们上面随意放一个点即可。

  方案按照乘法原理算出即可。

B.Islands II

  将边界作为岛0,显然,岛0包括了所有的岛。

  将相邻的岛用边连接后,从0开始向下进行tarjan dfs。

  若low[v]>=dfn[u],则说明这颗搜索树都被u包裹着。

  这样就能统计出答案了。

  (我不喜欢割点的说法,令人发晕)

C.Transfer Window

  考场上觉得这道好做,结果W了……

  显然可以floyd或暴力处理出闭包,统计出一个球员可以换成那些球员。

  然后建二分图,跑最大流。

  方案不会输……还在调。

D.National Property

  坑先放这,再填。

E.George and Interesting Graph

  先枚举中心点,对于每个中心点,先满足自环(interesting)和双向边的条件。

  再无视中心点,试图满足最后一个条件。

  先考虑删最少的边,我们发现,外围的点入度和出度不能超过1。

  于是建二分图,跑最大流,得到删边数。

  因为外围肯定用的边数和点数相同,所以用点数-保留边数就是加边数了。

附代码:

 A:

 B:

#include<cstdio>
#include<cstring>
#define max(a,b) (a>b?a:b)
#define min(a,b) (a<b?a:b)
inline int read(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9') {if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') {x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
struct edge{
    int to;
    int ne;
}e[5000500];
int h[1000500],cnt;
void add(int a,int b){
    e[++cnt]=(edge){b,h[a]};
    h[a]=cnt; return ;
}
int maps[1050][1050],ans[1000050],ils;
int n,m,siz[1000050],dfn[1000050],low[1000050],nti;
bool vis[1000050];
void dfs(int x){
    siz[x]=1;vis[x]=1;
    for(int i=h[x];i;i=e[i].ne){
        if(!vis[e[i].to]){
            dfs(e[i].to);
            siz[x]+=siz[e[i].to];
        }
    }
    return ;
}
void tjw(int x,int fa){
    low[x]=dfn[x]=++nti;
    for(int i=h[x];i;i=e[i].ne){
        if(e[i].to==fa) continue;
        if(!dfn[e[i].to]){
            tjw(e[i].to,x);
            low[x]=min(low[x],low[e[i].to]);
            if(low[e[i].to]>=dfn[x]) ans[x]+=siz[e[i].to];
        }
        else low[x]=min(low[x],dfn[e[i].to]);
    }
    return ;
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++)
            maps[i][j]=read(),
            ils=max(ils,maps[i][j]);
    }
    for(int i=0;i<=n+1;i++){
        for(int j=0;j<=m+1;j++){
            add(maps[i][j],maps[i+1][j]);
            add(maps[i+1][j],maps[i][j]);
            add(maps[i][j],maps[i][j+1]);
            add(maps[i][j+1],maps[i][j]);
        }
    }
    dfs(0);
    tjw(0,-1);
    for(int i=1;i<=ils;i++) printf("%d ",ans[i]);
    return 0;
}

 C:

 D:

 E:

 

posted @ 2018-06-25 22:38  臼邦庶民  阅读(148)  评论(0编辑  收藏  举报