zoj 3583 Simple Path

题意:给定一个无向图,输出不在s到d的简单路径上的点

题解:

1方法1dfs

先删点,然后从(前提:删除的不是s且s没有被拜访)s搜一次,再从(前提:删除的不是d且d没有被拜访)d搜一次,搜不到的点就是不再s到d简单路径上的点。

一开始错在这个图上了:

从0到4

0 1

0 2

0 3

0 4

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
bool v[111],not_in[111],a[111][111];
int n,m,s,d;
void dfs(int x)
{
    for(int i=0;i<=n-1;i++)
    if((!v[i])&&a[x][i])
    {
        v[i]=true;
        dfs(i);
    }
}
int main()
{
    while(scanf("%d%d%d%d",&n,&m,&s,&d)!=EOF)
    {
        memset(a,false,sizeof(a));
        memset(not_in,false,sizeof(not_in));
        for(int i=1;i<=m;i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            a[u][v]=true;
            a[v][u]=true;
        }
        for(int i=0;i<=n-1;i++)
        {
            memset(v,false,sizeof(v));
            v[i]=true;
            if(!v[s])dfs(s);//必须加上!v
            if(!v[d])dfs(d);//必须加上!v
            /*
            0 1
            0 2
            0 3
            0 4
            看这种图,必须删除点s后才能发现不在简单路径上的点。
            */
            for(int j=0;j<=n-1;j++)
            if(!v[j]&&j!=s&&j!=d)not_in[j]=true;
        }
        int ans=0;
        for(int i=0;i<=n-1;i++)
        if(not_in[i])ans++;
        printf("%d\n",ans);
    }
    return 0;
}

2.建立网络流模型求解

注意本题有重边,必须处理重边否则会出现错误。

建立图的依据:u如果不在简单路径上,则有s->u的路径与d->u的路径必然会经过同一个点。

方法:

建立超级汇点ss,超级源点dd,ss到s连流量为1的边,dd到d连流量为1的边。原图中的边流量设为无穷。对于每个点拆点,之间流量为1.但是对于u这个点,流量为2。

u和超级汇点也连边。

求超级源点到超级汇点的流量。

#include<iostream>
#include<cstdio>
#include<cstring>
#define INF (1<<26)
using namespace std;
template <int MAXSIZE,int MAXQ>
class DINIC//建立对象时先调用清除函数
{
 public:
   void clear(int n0)
   {
     m=0;n=n0;
     memset(edge,-1,sizeof(edge));
     memset(next,-1,sizeof(next));
    }

   void addedge(int u,int v,int c)
   {
    to[m]=v;
    cap[m]=c;
    next[m]=edge[u];
    edge[u]=m++;

    to[m]=u;
    cap[m]=0;
    next[m]=edge[v];
    edge[v]=m++;
    }

   bool bfs()
   {
    for(int i=0;i<=n;i++)
     d[i]=-1;
    int head=0,tail=0,x,y;
    d[s]=0;q[0]=s;
    while(head<=tail)
    {
        x=q[head];head=(head+1)%MAXQ;int i=edge[x];
        while(i!=-1)
        {
        y=to[i];
        if(cap[i] && d[y]==-1)
        {
        d[y]=d[x]+1;
        if(y==t)return true;
        tail=(tail+1)%MAXQ;q[tail]=y;
         }
        i=next[i];
        }
    }
    return false;
    }

    int find(int x,int low=INF)
   {
    if(x==t)return low;
    int ret,y,ans=0,i=edge[x];
    while(i!=-1 && low>0)
    {
        y=to[i];
        if(cap[i]>0 && d[y]==d[x]+1 && (ret=find(y,min(low,cap[i]))))
        {
        cap[i]-=ret;
        cap[i^1]+=ret;
        low-=ret;
        ans+=ret;
        }
        i=next[i];
    }
    return ans;
    }

    int dinic(int s0,int t0)
   {
    s=s0;t=t0;
    int ans=0;
    while(bfs())
    ans+=find(s);
    return ans;
    }
 private:
    int m,s,t,n;
    int to[MAXSIZE],cap[MAXSIZE],next[MAXSIZE],edge[MAXSIZE],d[MAXSIZE],q[MAXQ];
};
DINIC<60010,600000> a;
bool g[201][201];
int main()
{
    int n,m,s,d,supers,supert;
    while(scanf("%d%d%d%d",&n,&m,&s,&d)!=EOF)
    {
        memset(g,false,sizeof(g));
        for(int i=1;i<=m;i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            g[u][v]=true;
            g[v][u]=true;
        }
                 //s,t
        int ans=0;
        for(int i=0;i<=n-1;i++)
        if(i!=s && i!=d)
        {
            a.clear(2*n+1);
            supers=2*n;supert=2*n+1;
            a.addedge(supers,s,1);
            a.addedge(supers,d,1);
            a.addedge(i+n,supert,2);

            for(int x=0;x<=n-1;x++)
             for(int y=0;y<=n-1;y++)
              if(g[x][y])
              a.addedge(x+n,y,INF);

            for(int j=0;j<=n-1;j++)
            if(j!=i)
                a.addedge(j,j+n,1);
            else
                a.addedge(j,j+n,2);
            int sum=a.dinic(supers,supert);
            if(sum<=1)
            ans++;
        }
        printf("%d\n",ans);
    }
   return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值