bzoj 1001: [BeiJing2006]狼抓兔子

http://www.lydsy.com/JudgeOnline/problem.php?id=1001

 

解法1:直接最小割dinic || isap ,据说会卡掉某些人写的丑的dinic

 

/**************************************************************
    Problem: 1497
    User: 11101001
    Language: C++
    Result: Accepted
    Time:576 ms
    Memory:15356 kb
****************************************************************/
 
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int maxn = 600001;
const int INF = 0x7fffffff;
int n,m,dis[maxn],head[maxn],que[maxn];
struct node{
    int v,w,next;
}edge[maxn];
int ans,tmp,S,T,num=1;
inline void Add_Edge(int u,int v,int w)
{
    edge[++num].v=v;edge[num].w=w;edge[num].next=head[u];head[u]=num;
    edge[++num].v=u;edge[num].next=head[v];head[v]=num;
}
bool bfs()
{
    memset(dis,-1,sizeof(dis));
    int h=0,t=1;
    que[h]=dis[0]=0;
    while(h<t)
    {
        int u=que[h++];
        if(h==maxn)h=0;
        for(int i=head[u];i;i=edge[i].next)
        {
            int v=edge[i].v;
            if(edge[i].w&&dis[v]<0)
            {
                que[t++]=v;
                dis[v]=dis[u]+1;
                if(t==maxn)t=0;
            }
        }
    }
    if(dis[T]==-1)return false;
    return true;
}
int dfs(int x,int f)
{
    if(x==T) return f;
    int mn=0,w;
    for(int i=head[x];i;i=edge[i].next)
    {
        if(edge[i].w&&dis[edge[i].v]==dis[x]+1)
        {
            w=f-mn;
            w=dfs(edge[i].v,min(w,edge[i].w));
            edge[i].w-=w;
            edge[i^1].w+=w;
            mn+=w;
            if(mn==f)return f;
        }   
    }
    if(!mn)dis[x]=-1;
    return mn;
}
void dinic()
{
    while(bfs())
        ans+=dfs(S,INF);
}
int main()
{
    S=0;
    scanf("%d%d",&n,&m);T=n+m+1;
    for(int a,i=1;i<=n;i++){
        scanf("%d",&a);
        Add_Edge(S,i,a);
    }
    for(int a,b,c,i=1;i<=m;i++)
    {
        scanf("%d%d%d",&a,&b,&c);
        Add_Edge(a,n+i,INF);
        Add_Edge(b,n+i,INF);
        Add_Edge(n+i,T,c);
        tmp+=c;
    }
    dinic();
//  printf("%d %d\n",tmp,ans);
    printf("%d\n",tmp-ans);
    return 0;
}
Dinic

 

解法2:平面图转对偶图最短路.

 

/**************************************************************
    Problem: 1001
    User: 11101001
    Language: C++
    Result: Accepted
    Time:2900 ms
    Memory:120432 kb
****************************************************************/
 
#include<iostream>
#include<cstring>
#include<cstdio>
#define maxn 2000001
using namespace std;
int n,m,to;
struct data{
    int v,next,w;
}edge[4*maxn];
int dis[maxn],q[maxn],head[maxn];
bool vis[maxn];
int num;
inline void add_edge(int u,int v,int w)
{
    edge[++num].v=v;edge[num].w=w;edge[num].next=head[u];head[u]=num;   
    edge[++num].v=u;edge[num].w=w;edge[num].next=head[v];head[v]=num;
}
void spfa()
{
    memset(dis,0x3f,sizeof(dis));
    int t=0,w=1;
    dis[0]=q[w]=0;vis[0]=1;
    while(t!=w)
    {
        int u=q[t++];
        vis[u]=0;
        if(t==maxn)t=0;
        for(int i=head[u];i;i=edge[i].next)
        {
            int v=edge[i].v;
            if(dis[v]>dis[u]+edge[i].w)
            {
                dis[v]=dis[u]+edge[i].w;
                if(!vis[v])
                {
                    vis[v]=1;
                    q[w++]=v;
                    if(w==maxn)w=0;
                }
            }
        }
    }
}
inline void init()
{
        int x;
    for(int j=1;j<m;j++)
    {
        scanf("%d",&x);
        add_edge(j,to+1,x);
    }
    for(int i=1;i<n-1;i++)
    {
        for(int j=1;j<m;j++)
        {
            scanf("%d",&x);
            add_edge((i*2)*(m-1)+j,((i*2)-1)*(m-1)+j,x);
        } 
    }
    for(int j=1;j<m;j++)
    {
        scanf("%d",&x);
        add_edge(0,((n*2)-3)*(m-1)+j,x);
    }
    for(int i=0;i<n-1;i++)
    {
        for(int j=1;j<=m;j++)
        {
            scanf("%d",&x);
            if(j==1)add_edge(0,(i*2)*(m-1)+m,x);
            else if(j==m)add_edge((i*2+1)*(m-1),to+1,x);
            else add_edge((i*2)*(m-1)+j-1,(i*2)*(m-1)+j+m-1,x);
        }
    }
    for(int i=0;i<n-1;i++)
    {
        for(int j=1;j<m;j++)
        {
            scanf("%d",&x);
            add_edge((i*2+1)*(m-1)+j,(i*2)*(m-1)+j,x);
        }
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    to=(n*m-m-n+1)*2;
    init();
    spfa();
    printf("%d\n",dis[to+1]);
    return 0;
}

 

posted @ 2017-12-24 08:20  zzzzx  阅读(235)  评论(0编辑  收藏  举报