poj-2175 Evacuation Plan

版权声明:最后一年,加油~ https://blog.csdn.net/zzti_xiaowei/article/details/81326351

[题目链接]

思路:

  • 题目要求输出比样例更优的任意一个解,用最小费用流建模求出最优解会TLE。
  • 某个流f是同流量中的最小费用流,等价于f的残余网络中没有负圈。<最小费用流的证明>
  • 构造残余网络,从汇点开始遍历,因为源点s发出的边满流了,即没有容量为0。用spfa算法找负圈,注意跳出的点不一定在负圈上(可能是与负圈有多个边相连的点,也会多次更新)!然后更新一下负圈上的点即可。

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<vector>
#include<cmath>
#include<algorithm>
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
const int Max_v=1100;

int N,M;
struct Node{
    int x,y,c;
}no[Max_v];
int E[Max_v][Max_v];
int d[Max_v][Max_v]; //距离矩阵

int dist[Max_v],cnt[Max_v],prv[Max_v];
bool used[Max_v];

void spfa(int t){
    memset(dist,0x3f,sizeof(dist));
    memset(cnt,0,sizeof(cnt));
    memset(used,0,sizeof(used));
    queue<int>que;
    que.push(t);
    dist[t]=0;used[t]=1;cnt[t]=1;
    while(!que.empty()){
        int u=que.front();que.pop();
        used[u]=0;
        for(int i=0;i<=t;i++){
            if(d[u][i]!=inf&&dist[i]>dist[u]+d[u][i]){
                dist[i]=dist[u]+d[u][i];
                prv[i]=u;
                if(!used[i]){
                    used[i]=1;cnt[i]++;
                    que.push(i);
                    if(cnt[i]>t){
                        printf("SUBOPTIMAL\n");
                        memset(used,0,sizeof(used));
                        used[i]=1;
                        int sta; //找到一个负圈上的点
                        for(int j=prv[i];!used[j];j=prv[j]){
                            used[j]=1;
                            sta=j;
                        }
                        int u=prv[sta],v=sta;
                        do{ 
                            if(u>N)E[v][u]--;
                            else E[u][v]++;
                            v=u;u=prv[u];
                        }while(v!=sta);
                        for(int i=1;i<=N;i++){
                            for(int j=N+1;j<=N+M;j++)
                                printf("%d%c",E[i][j],j==N+M?'\n':' ');
                        }
                        return;
                    }
                }
            }
        }
    }
    printf("OPTIMAL\n");
}

int main()
{
    scanf("%d%d",&N,&M);
    for(int i=1;i<=N+M;i++){
        scanf("%d%d%d",&no[i].x,&no[i].y,&no[i].c);
    }
    int s=0,t=N+M+1;
    memset(d,0x3f,sizeof(d));
    int x[Max_v],y[Max_v];
    memset(x,0,sizeof(x));
    memset(y,0,sizeof(y));
    for(int i=1;i<=N;i++){ //构造残余网络
        for(int j=N+1;j<=N+M;j++){
            scanf("%d",&E[i][j]);
            x[i]+=E[i][j];
            y[j]+=E[i][j];
            int cost=abs(no[i].x-no[j].x)+abs(no[i].y-no[j].y)+1;
            d[i][j]=cost;
            if(E[i][j]>0)d[j][i]=-cost;
        }
    }
    for(int i=1;i<=N;i++){
        if(x[i]<no[i].c)d[s][i]=0;
        if(x[i])d[i][s]=0;
    }
    for(int i=N+1;i<=N+M;i++){
        if(y[i]<no[i].c)d[i][t]=0;
        if(y[i])d[t][i]=0;
    }
    spfa(t);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/zzti_xiaowei/article/details/81326351