2018.3.5

1、

706. [最小割模板]巡逻

题目描述
FJ有个农场,其中有n块土地,由m条边连起来。FJ的养牛场在土地1,在土地n有个新开张的雪糕店。Bessie经常偷偷溜到雪糕店,当Bessie去的时候,FJ就要跟上她。但是Bessie很聪明,她在从雪糕店返回时不会经过去雪糕店时经过的农场,因此FJ总是抓不住Bessie。 为了防止Bessie生病,FJ决定把一些诚实的狗放在一些土地(1和n除外)上,使Bessie无法在满足每块土地最多只经过一次的条件的情况下,从养牛场溜到雪糕店然后又溜回养牛场。 求出FJ最少要放多少只狗。数据保证1和n间没有直接的连边。

输入格式
Line 1: Two integers: N and M.

Lines 2..M+1: Each line contains two integers A and B that describea trail joining fields A and B. It is possible to travelalong this trail both ways. No trail will appear twice.

输出格式
Line 1: A single integer that tells how many fields FJ should guard.

input

6 7
1 2
2 6
1 3
3 4
3 5
4 6
5 6
output

1

OUTPUT DETAILS:

FJ can guard field 2 (for example). FJ could guard both fields 4 and
5, but that would require more dogs.
数据规模与约定
数据范围:n<=1000,m<=10000。
时间限制:1s
空间限制:256MB

一道最小割的模板题
显而易见的,我们可以想到把第i个点拆成i和i+n,把两个点连起来,权值为1。那么最小割问题就转化为最大流了。
这道题的问题就是两个点之间的边到底怎么连。
i为入点,i+n为出点。
那么所有由出点到入点的边权值为0。
由入点到出点的边权值为1(任意正整数都行)。
所以对于两个点a,b
我们只要insert(a+n,b,1),(b+n,a,1) 那么只要套一下dinic模板就行了。

#include<bits/stdc++.h>
using namespace std;
const int oo=165430000;
bool check;
int n,m,lazy,ans,linkk[21000],t,deep[21000],head,tail,q[21000];
struct node
{
    int n,y,v;
}e[1100000];
int read() 
{ 
    bool flag=true; 
    int num=0;char c=getchar(); 
    for(;c<'0'||c>'9';c=getchar())if(c=='-') flag=false; 
    for(;c>='0'&&c<='9';c=getchar()) 
    num=(num<<3)+(num<<1)+c-48; 
    if(flag) return num; 
     else return -num; 
} 
void insert(int aa,int bb,int cc)
{
    e[++t].n=linkk[aa];
    e[t].y=bb;
    e[t].v=cc;
    linkk[aa]=t;
    e[++t].n=linkk[bb];
    e[t].y=aa;
    e[t].v=0;
    linkk[bb]=t;
    return;
} 
void init()
{
    n=read();m=read();
    int aa,bb;
    t=1;
    for(int i=1;i<=m;++i) //点①
     {
        aa=read();bb=read();
        if(aa>bb) swap(aa,bb);
        if(aa!=1)
          insert(aa+n,bb,oo),insert(bb+n,aa,oo);
        else
          insert(1,bb,oo),insert(bb,1,oo);
     }
     for(int i=2;i<=n-1;++i)
      insert(i,i+n,1);
     return;
}
int dfs(int x,int lazy)
{
    if(x==n)return lazy;
    int nowlazy=0;
    int d=0;
    for(int i=linkk[x];i&&nowlazy<lazy;i=e[i].n)
     {
      int v=e[i].y;
      if(deep[v]==deep[x]+1&&e[i].v>0) 
       if(d=dfs(v,min(e[i].v,lazy-nowlazy)))
        {
          nowlazy+=d;
          e[i].v-=d;
          e[i^1].v+=d;
        } 
     }
    if(nowlazy==0) deep[x]=-1;
    return nowlazy;
}
void bfs()
{
    memset(deep,-1,sizeof(deep));
    deep[1]=0;head=tail=1;
    q[1]=1; 
    while(head<=tail)
     {
       int v=q[head];
       for(int i=linkk[v];i;i=e[i].n)
        if(deep[e[i].y]==-1&&e[i].v>0) deep[e[i].y]=deep[v]+1,q[++tail]=e[i].y;
       head++;
     } 
    if(deep[n]!=-1) check=true;
    return;
}
int main()
{
    init();
    check=true;
    while(check)
     {
        int d=0;check=false;
        bfs();
        if(!check) break;
        while(d=dfs(1,oo)) ans+=d;
     }
    if(ans!=0)
     printf("%d",ans-1);
    else printf("0");   
    return 0;
}

tarjan题写的太少了 模拟赛gg了,于是复习一下tarjan。

2、

336. 【dfn】交换机

题目描述
n个城市之间有通讯网络,每个城市都有通讯交换机,直接或间接与其它城市连接。因电子设备容易损坏,需给通讯点配备备用交换机。

但备用 交换机数量有限,不能全部配备,只能给部分重要城市配置。

于是规定:如果某个城市由于交换机损坏,不仅本城市通讯中断,还造成其它城市通讯中断,则配备备 用交换机。

请你根据城市线路情况,计算需配备备用交换机的城市个数,及需配备备用交换机城市的编号。

友情提示:图论常见的坑点,重边,自环,还有对本题来说的不连通

输入格式
第一行,一个整数n,表示共有n个城市(2<=n<=20000)

下面有若干行(<=60000):每行2个数a、b,a、b是城市编号,表示a与b之间有直接通讯线路。

输出格式
第一行,1个整数m,表示需m个备用交换机,下面有m行,每行有一个整数,表示需配备交换机的城市编号,输出顺序按编号由小到大。如果没有城市需配备备用交换机则输出0。

样例数据
input

7
1 2
2 3
2 4
3 4
4 5
4 6
4 7
5 6
6 7
output

2
2
4
数据规模与约定
gdoi

时间限制:1s1s
空间限制:256MB

#include<bits/stdc++.h>
using namespace std;
int n,m,linkk[21000],t,root,dfn[21000],low[21000],ind,tot,ans[21000];
bool flag[21000];
struct node{
    int n,y;
}e[121000];
int read() { 
    bool flag=true; 
    int num=0;char c=getchar(); 
    for(;c<'0'||c>'9';c=getchar())if(c=='-') flag=false; 
    for(;c>='0'&&c<='9';c=getchar()) 
    num=(num<<3)+(num<<1)+c-48; 
    if(flag) return num; 
     else return -num; 
} 
void insert(int aa,int bb){
    e[++t].n=linkk[aa];
    e[t].y=bb;
    linkk[aa]=t;
    e[++t].n=linkk[bb];
    e[t].y=aa;
    linkk[bb]=t;
    return;
}
void tarjan(int x){
    dfn[x]=low[x]=++ind;
    int son=0;
    for(int i=linkk[x];i;i=e[i].n){
        int v=e[i].y;
        if(!dfn[v]){
            tarjan(v);
            son++;
            if(low[v]<low[x]) low[x]=low[v];
            if(!flag[x])
            if( ((x == root) && (son > 1)) || ( ( x != root ) && (low[v] >= dfn[x]) ) )
             tot++,flag[x]=true;
        }
        else
         if(dfn[v]<low[x])
          low[x]=dfn[v];
     }
    return;
}
void init(){
    n=read();
    int aa,bb;
    while(scanf("%d",&aa)!=EOF){
        bb=read();
        insert(aa,bb);
    }
    for(int i = 1;i <= n;++i)
        if(!dfn[i]){
        root=i;
        tarjan(i);
    }
    return;
}
int main() {
    init();
    sort(ans+1 , ans+1+tot);
    printf("%d\n",tot);
    for(int i = 1;i <= n;++i)
     if(flag[i]) printf("%d\n",i);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/a1035719430/article/details/79450174