[2018雅礼省选集训3-30]path 平面图最短路最小割

根据题意,题目给定的图是一个平面图。如果把1号点到不了的点和到不了n号点的点及所连边删掉,那么图就大概是有一条1n的链,然后还有一些边覆盖在上面,这样的话它的对偶图就大概是一棵树。
再考虑颜色限制怎么搞,假设x与其父亲的边在原图中代表边(u,v),那么xT割就表示不选u+1,...,v1这些点的颜色,于是对于每个颜色建一个点,然后xu+1,...,v1的颜色的点连容量正无穷的双向边。注意到xT割,那么其子树都在T割,因此x只需要向未被更底层边覆盖的点就可以了。
还有一个细节,注意到一个DAG的对偶图还是一个DAG,且对于任何一条ST的路径一定存在一条边(u,v)使得Su上的点在S割,vT上的点全在T割(就是不会S,T间隔,这样才对应原图一个合法路径),那么加上颜色限制后可能破坏这一点,所以在本题对偶图中每个点要向其父亲连一条容量为正无穷的边保证这一点。
代码:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<algorithm>
#define N 1010
using namespace std;
const int inf=0x3f3f3f3f;
int n,m,c[N],z[N],S,T,dl[N<<1],ne[N<<1],st[N];
vector<int> gt[N],gr[N],tr[N];
bool bt[N],br[N];
struct node
{
    int x,y,w;
}e[N];
struct edge
{
    int t,c,f;
    edge *next,*rev;
}*con[N<<1];
void ins(int x,int y,int c)
{
    edge *p=new edge;p->t=y;p->c=c;p->f=0;p->next=con[x];con[x]=p;
    p=new edge;p->t=x;p->c=0;p->f=0;p->next=con[y];con[y]=p;
    con[x]->rev=con[y];con[y]->rev=con[x];
}
bool cmp(node p,node q)
{
    if(p.y-p.x==q.y-q.x) return p.x<q.x;
    return (p.y-p.x<q.y-q.x);   
}
bool bfs()
{
    memset(ne,0,sizeof(ne));
    ne[S]=1;dl[1]=S;bool re=0;
    for(int hd=1,tl=1,v=S;hd<=tl;re|=(v==T),v=dl[++hd])
        for(edge *p=con[v];p;p=p->next)
            if(p->c>p->f&&ne[p->t]==0) ne[p->t]=ne[v]+1,dl[++tl]=p->t;
    return re;
}
int dinic(int v,int flow)
{
    if(v==T) return flow;
    if(ne[v]==-1) return 0;
    int re=0;
    for(edge *p=con[v];p&&flow;p=p->next)
        if(p->c>p->f&&ne[p->t]==ne[v]+1)
        {
            int o=dinic(p->t,min(flow,p->c-p->f));
            p->f+=o;re+=o;
            p->rev->f-=o;flow-=o;
        }
    if(!re) ne[v]==-1;
    return re;  
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<n;i++)
        {scanf("%d",&c[i]);z[i]=c[i];}
    for(int i=1;i<=m;i++)
    {   
        scanf("%d%d%d",&e[i].x,&e[i].y,&e[i].w);
        gt[e[i].x].push_back(e[i].y);
        gr[e[i].y].push_back(e[i].x);
    }
    bt[0]=1;
    for(int i=0;i<=n;i++)
        if(bt[i])
            for(int j=0;j<gt[i].size();j++)
                bt[gt[i][j]]=1;
    br[n]=1;
    for(int i=n;i>=0;i--)
        if(br[i])
            for(int j=0;j<gr[i].size();j++)
                br[gr[i][j]]=1;
    if(!bt[n])
    {
        puts("-1");
        return 0;
    }
    int mm=m;m=0;
    for(int i=1;i<=mm;i++)
        if(bt[e[i].x]&&bt[e[i].y]&&br[e[i].x]&&br[e[i].y]) e[++m]=e[i];
    sort(e+1,e+m+1,cmp);
    S=0;T=n+m+1;
    for(int i=1;i<=m;i++)
    {
        int v=S;
        for(int j=i+1;j<=m;j++)
            if(v||(e[j].x<=e[i].x&&e[j].y>=e[i].y)) {v=j;break;}
        tr[v].push_back(i);
    }
    for(int i=0;i<=m;i++)
        for(int j=0;j<tr[i].size();j++)
            ins(i,tr[i][j],e[tr[i][j]].w),ins(tr[i][j],i,inf);
    for(int i=0;i<=m;i++)
    {
        int top=0;
        for(int j=0;j<tr[i].size();j++)
            st[++top]=e[tr[i][j]].x;
        sort(st+1,st+top+1);
        for(int j=2;j<=top;j++) 
            ins(i,c[st[j]]+m,inf),ins(c[st[j]]+m,i,inf);
    }
    for(int i=1;i<=m;i++)
        if(!tr[i].size())
        {
            ins(i,T,inf);
            for(int j=e[i].x+1;j<e[i].y;j++)
                ins(i,c[j]+m,inf),ins(c[j]+m,i,inf);
        }
    int ans=0;
    while(bfs()) ans+=dinic(S,inf);
    if(ans<inf) printf("%d",ans);
    else puts("-1");    
    return 0;
}
阅读更多
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/DOFYPXY/article/details/79967638
个人分类: 网络流 最短路
上一篇[2018雅礼省选集训3-30]program
下一篇[BZOJ2098]又是nand 树链剖分+位运算
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭