poj 2175 费用流消圈

时间:2022-10-30 09:49:26

题意抽象出来就是给了一个费用流的残存网络,判断该方案是不是最优方案,如果不是,还要求给出一个更优方案。

在给定残存网络上检查是否存在负环即可判断是否最优。

沿负环增广一轮即可得到更优方案。

考虑到制作模板的需要,我用前向星建图做的。此题用邻接矩阵应该更方便。

#include<queue>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
const int maxn=220;
const int MAXN=41000;
int nbuild,nshelt;
int x[maxn],y[maxn];
int tot,S,T;
int pointer[maxn];
int toT[MAXN];
int flo[maxn][maxn];
const int INF=0x3f3f3f;
int dis[maxn],pre[maxn],in[maxn],use[maxn];
bool vis[maxn];
bool visit[maxn];
struct Edge
{
    int to,next,cap,f,w;
    Edge() {};
    Edge(int b,int c,int nxt,int flow,int weight) {to=b,cap=c,next=nxt,f=flow,w=weight;}
}edge[MAXN];
inline void addedge(int a,int b,int c,int flow,int w1)
{
    edge[tot]=Edge(b,c,pointer[a],flow,w1);
    pointer[a]=tot++;
    edge[tot]=Edge(a,0,pointer[b],-flow,-w1);
    pointer[b]=tot++;
}
inline int cost(int a,int b)
{
    return abs(x[a]-x[b])+abs(y[a]-y[b])+1;
}
void init()
{
    int t;
    memset(pointer,-1,sizeof(pointer));
    memset(visit,0,sizeof(vis));
    tot=0;
    S=0;T=nbuild+nshelt+1;
    rep(i,1,nbuild)
    {
        scanf("%d%d%d",&x[i],&y[i],&t);
        addedge(S,i,t,t,0);
    }
    rep(i,nbuild+1,nbuild+nshelt)
    {
        scanf("%d%d%d",&x[i],&y[i],&t);
        toT[i]=tot;
        addedge(i,T,t,0,0);

    }
    int aedge;
    rep(i,1,nbuild)
    {
        rep(j,1,nshelt)
        {
            scanf("%d",&t);
            addedge(i,nbuild+j,INF,t,cost(i,nbuild+j));
          //  printf("%d-->%d w=%d\n",i,nbuild+j,cost(i,nbuild+j));
            flo[i][j]=t;
            aedge=toT[nbuild+j];
            edge[aedge].f+=t;
            edge[aedge^1].f-=t;
        }
    }


}
int ve=0;
void clearcircle()
{
    memset(use,0,sizeof(use));
    int enter;
    while(1)
    {
        use[ve]++;
       // printf("ve=%d\n",ve);
        if(use[ve]>=2) {enter=ve;break;}
        ve=edge[pre[ve]^1].to;
    }
    int sub;
    do
    {
        sub=edge[pre[ve]^1].to;
        edge[pre[ve]].f+=1;
        edge[pre[ve]^1].f-=1;
        ve=sub;
    }while(ve!=enter);
    rep(i,1,nbuild)
    {
        for(int j=pointer[i];j!=-1;j=edge[j].next)
        {
            int v=edge[j].to;

            if(v>nbuild) flo[i][v-nbuild]=edge[j].f;
        }
    }

}
int searchcircle(int s)
{
    queue<int> q;
    rep(i,S,T)
    {
        dis[i]=INF;
        vis[i]=0;
        pre[i]=-1;
        in[i]=0;
    }
    q.push(s);
    vis[s]=1;
    in[s]++;dis[s]=0;
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        vis[u]=0;
     //   printf("%d dis[u]=%d\n",u,dis[u]);
        for(int j=pointer[u];j!=-1;j=edge[j].next)
        {
            int v=edge[j].to;
   // printf("%d-->%d vis[v]=%d dis[v]=%d ds[u]=%d edge[j].w=%d\n",u,v,vis[v],dis[v],dis[u],edge[j].w);
            if(edge[j].cap-edge[j].f&&dis[v]>dis[u]+edge[j].w)
            {
                dis[v]=dis[u]+edge[j].w;
                pre[v]=j;
                // printf("%d-->%d vis[v]=%d dis[v]=%d ds[u]=%d edge[j].w=%d\n",u,v,vis[v],dis[v],dis[u],edge[j].w);
                if(!vis[v])
                {
                    vis[v]=1;
                    visit[v]=1;
                    in[v]++;
                    q.push(v);
                    if(in[v]>=T)
                    {
                        ve=v;
                        return 1;
                    }
                }
            }
        }
    }
    return 0;

}
int main()
{
 //   freopen("in.txt","r",stdin);
    while(scanf("%d",&nbuild)==1)
    {
        scanf("%d",&nshelt);
        init();
        /*rep(i,1,nbuild)
        {
            rep(j,1,nshelt) printf("%d ",flo[i][j]);
            printf("\n");
        }
        rep(i,1,nbuild)
        {
            rep(j,1,nshelt) printf("%d ",cost(i,nbuild+j));
            printf("\n");
        }*/
        int flag=0;
        ve=0;
        rep(i,S,T)
        {
            if(visit[i]) continue;
            ve=searchcircle(i);
            if(ve)
            {
                flag=1;
                printf("SUBOPTIMAL\n");
                clearcircle();
                rep(i,1,nbuild)
                {
                    rep(j,1,nshelt) printf("%d ",flo[i][j]);
                    printf("\n");
                }
                break;
            }
        }
        if(!flag) printf("OPTIMAL\n");

    }
    return 0;
}