poj 2175 Evacuation Plan 最小费,判断负圈的存在

开始悲剧的tle了。。。又检查了一遍代码。。发现没有错啊!!!最后逛了一下神犇们的博客发现了这段话!!!!!spfa的时候沿途记录每个点是由哪个点更新来的。那么,在第n+1次入队的时候的那个循环,我们就一定可以得到一个负权环。顺着最后那个点往前找环。注意!由于更新的复杂性,最后那个点不一定在最终负环里(依赖于spfa的写法)”  

fuck!!!

next,我隐约感觉spfa判断负圈应该可以优化啊!!?否则那个进出 n 次后跳出和水的一逼的 bellman-ford 算法有什么区别!!!!尼玛有什么区别啊!!!复杂度就差不多了啊!!!还不如直接用 bellman-ford 啊!!!!!!!!有木有啊!!!可是怎么优化呢....? 

#include<vector>
#include<cstring>
#include<string>
#include<cstdio>
#include<iomanip>
#include<queue>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<map>
#include<cassert>
#include<cmath>
#include<stack>
using namespace std;
#define abs(a) ((a)>0?(a):-(a))

const int maxn = 111;
const int maxc = 222;
const int end = 201;
const int add = 100;
const int inf = 0x3f3f3f3f;

int n,m,over;
int x10[maxn];
int y10[maxn];
int x20[maxn];
int y20[maxn];
int fb[maxn];
int tc[maxn];
int back[maxc];
int way[maxc];
int num[maxc];
int c[maxc][maxc];
int fnm[maxn][maxn];
int f[maxc][maxc];
int cost[maxc][maxc];
vector<int>g[maxc];
queue<int>q;
bool inq[maxc];
bool vis[maxc];

void init()
{
    memset(c,0,sizeof(c));
    memset(f,0,sizeof(f));
    memset(cost,0,sizeof(cost));
    memset(back,-1,sizeof(back));
    memset(fnm,0,sizeof(fnm));
    for(int i=0;i<=end;i++)
    {
        g[i].clear();
    }
    return ;
}

inline int d12(int x10, int y10, int x20, int y20)
{
    return abs( x10 - x20) + abs( y10 - y20) + 1;
}

void build()
{
    for(int i=1;i<=n;i++)
    {
        c[0][i] = fb[i];
    }
    for(int i=1;i<=m;i++)
    {
        c[i+add][end] = tc[i];
    }
    int now,to;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            now = i;
            to = j+add;
            c[now][to] = inf;
            f[now][to] = fnm[i][j];
            f[to][now] = -fnm[i][j];
            f[0][now] += fnm[i][j];
            f[now][0] -= fnm[i][j];
            f[to][end] += fnm[i][j];
            f[end][to] -= fnm[i][j];
        }
    }
    for(int i=1;i<=n;i++)
    {
        g[0].push_back(i);
        g[i].push_back(0);
    }
    for(int i=1;i<=m;i++)
    {
        now = i + add;
        g[now].push_back(end);
        g[end].push_back(now);
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            now = i;
            to = j + add;
            g[now].push_back(to);
            g[to].push_back(now);
        }
    }
    int temp;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            now = i;
            to = j + add;
            temp = d12 ( x10[i], y10[i], x20[j], y20[j] );
            cost[now][to] = temp;
            cost[to][now] = -temp;
        }
    }
    return ;
}

bool spfa()
{
    build();
    int now,to;
    for(int i=0;i<=n;i++)
    {
        way[i] = inf;
    }
    for(int i=1;i<=m;i++)
    {
        now = i+add;
        way[now] = inf;
    }
    memset(inq,false,sizeof(inq));
    while(!q.empty())
    {
        q.pop();
    }
    q.push(end);
    inq[end] = true;
    way[end] = 0;
    int temp;
    memset(num,0,sizeof(num));
    while(!q.empty())
    {
        now = q.front();
        q.pop();
        for(int i=0;i<g[now].size();i++)
        {
            to = g[now][i];
            if( c[now][to] > f[now][to] )
            {
                temp = way[now] + cost[now][to];
                if(temp < way[to])
                {
                    back[to] = now;
                    way[to] = temp;
                    num[to]++;
                    if(num[to] > maxc)
                    {
                        over = to;
                        return true;
                    }
                    if(!inq[to])
                    {

                        inq[to] = true;
                        q.push(to);
                    }
                }
            }
        }
        inq[now] = false;
    }
    return false;
}

int find()
{
    memset(vis,false,sizeof(vis));
    int temp = over;
    while(true)
    {
        if(vis[temp])
        {
            return temp;
        }
        vis[temp] = true;
        temp = back[temp];
    }
    assert(false);
}

void zz1215()
{
    if(spfa())
    {
        int temp = find();
        over = temp;
        int now,to;
        while(true)
        {
            if(back[temp] == over)
            {
                f[over][temp] ++;
                f[temp][over] --;
                break;
            }
            now = back[temp];
            to = temp;
            f[now][to]++;
            f[to][now]--;
            temp = back[temp];
        }
        printf("SUBOPTIMAL\n");
    //    cout<<"SUBOPTIMAL"<<endl;
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<m;j++)
            {
                now = i;
                to = j+add;
                printf("%d ",f[now][to]);
        //        cout<<f[now][to]<<" ";
            }
            printf("%d\n",f[i][m+add]);
       //     cout<<f[i][m+add]<<endl;
        }

    }
    else
    {
        printf("OPTIMAL\n");
    //    cout<<"OPTIMAL"<<endl;
    }
    return ;
}

int main()
{
  //  cin>>n>>m;
    while(cin>>n>>m)
    {
    init();
    for(int i=1;i<=n;i++)
    {
        scanf("%d%d%d",&x10[i],&y10[i],&fb[i]);
  //      cin>>x10[i]>>y10[i]>>fb[i];
    }
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d%d",&x20[i],&y20[i],&tc[i]);
  //      cin>>x20[i]>>y20[i]>>tc[i];
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            scanf("%d",&fnm[i][j]);
    //        cin>>fnm[i][j];
        }
    }
    zz1215();
    }
    return 0;
}





评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值