太空飞行计划问题

http://www.wikioi.com/problem/1233/

网络流最小费用问题
一开始看这个人的博客: http://blog.sina.com.cn/s/blog_61034ad90100eine.html,写了4天了,还是没能写出自己的代码。。。
后面面还有在这个OJ上AC了的代码。

照着这个人的代码打,还是没能想明白。。这个代码和这个OJ上的不同,是简化问题了的。只求最大收益
照着打的代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#define INF 999999
using namespace std;
//分别为残余网络,返回值,当前枚举的点,当前点的前驱,当前点到汇点的距离,距离为I的点数
int a[500][500],fh[500],now[500],pre[500],dis[500],sumd[500];
int n,m,ans;      //仪器数,实验数,收入
queue<int> q;

void cl()
{
    ans = 0;
    memset(a,0,sizeof(a));
    memset(fh,0,sizeof(fh));
    memset(now,0,sizeof(now));
    memset(pre,0,sizeof(pre));
    memset(dis,0,sizeof(dis));
    memset(sumd,0,sizeof(sumd));
    return ;
}

void input()
{
    int i,j,p;
    for(i = 1; i <= m; i++)
    {
        scanf("%d",&a[0][i]);  //原点为0第t个实验的收益
        ans+=a[0][i];          //累加收入
        while(scanf("%d",&p)&&p)
        {
            a[i][p+m] = INF;     //每个实验所需的实验仪器,t为实验编号,p为所需仪器编号
        }
    }
    for(i = m+1; i <= n+m; i++)
    {
        scanf("%d",&a[i][n+m+1]); //每个实验器材的成本,汇点为n+m
    }
    n = m+n+1;     //汇聚点更改
    return ;
}

void sap()
{
    int i,j,k,flow,minn;
    bool flag;
    sumd[0] = n+1;
    i = 0;
    flow = INF;
    while(dis[0] < n)
    {
        fh[i] = flow;  //保存返回值
        flag = false;
        for(j = now[i]; j <= n; j++)
        {
            if(a[i][j] > 0 && dis[i] == dis[j])   //满足有边,且距离之差为1
            {
                now[i] = j;  //更新访问节点
                flag = true;
                if(a[i][j]<flow)//更改该路上可通行的流量
                {
                    flow = a[i][j];
                }
                pre[j] = i;//记录前驱
                i = j;
                if(i == n)
                {
                    ans-=flow;   //减去这个流量
                    while(i!=0)
                    {
                        k = pre[i];
                        a[k][i]-=flow;
                        a[i][k]+=flow;
                        i = k;
                    }
                }
                break;
            }
        }
        if(flag)
        {
            continue;  //找不到增广路,不修改
        }
        minn = n+1;  //赋值为最大距离
        for(j = 0; j<=n; j++)
        {
            if(a[i][j]>0&&dis[j]<minn)
            {
                minn = dis[j];   //找到最小距离的点
                now[i] = j;      //更新前驱
            }
        }
        sumd[dis[i]]--;   //到该距离的总点数减一
        if(sumd[dis[i]]==0)    break;//中间没有点,有断层,无法找到增广路
        dis[i] = minn+1;  //距离加一
        sumd[dis[i]]++;   //到该距离的总点数加一
        if(i!=0)
        {
            i = pre[i];  //当前状态以改变,返回上一层
            flow = fh[i];
        }
    }
    printf("%d\n",ans);
    return ;
}

int main()
{
    while(scanf("%d%d",&m,&n)!=EOF)
    {
        cl();//初始化清空
        input();//输入数据
        /*for(int i=0; i<=m+n;i++)
        {
            for(int j=0; j<=m+n;j++)
            {
                printf("%6d ",a[i][j]);
            }
            printf("\n");
        }*/
        sap();
    }

    return 0;
}

在这个OJ网站上下的别人AC代码,慢慢看把。。T_T。。
代码:
#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
#include<iostream>
#define MAXL 1010
#define MAXN 100010
#define MAXM 1000010
#define oo 0x7FFFFFFF
using namespace std;
int first[MAXN], next[MAXM], v[MAXM], cost[MAXM], e;
int n;
int src, des;

bool flag;
bool vis[MAXL];
char str[MAXN];
vector<int> g[MAXL];
vector<int> test;
vector<int> app;
int a[MAXL];
inline void addEdge(int x, int y, int val)
{
    v[e] = y;
    cost[e] = val;
    next[e] = first[x];
    first[x] = e++;

    v[e] = x;
    cost[e] = 0;
    next[e] = first[y];
    first[y] = e++;
}
int SAP()
{
    int pre[MAXN], cur[MAXN], dis[MAXN], gap[MAXN];
    int flow = 0;
    int aug = oo;
    int x, y;
    bool flag;
    for (int i = 0; i < n; i++)
    {
        cur[i] = first[i];
        gap[i] = dis[i] = 0;
    }
    gap[src] = n;
    x = pre[src] = src;
    while (dis[src] < n)
    {
        flag = false;
        for (int &j = cur[x]; j != -1; j = next[j])
        {
            y = v[j];
            if (cost[j] > 0 && dis[x] == dis[y] + 1)
            {
                flag = true;
                aug = min(aug, cost[j]);
                pre[y] = x;
                x = y;
                if (x == des)
                {
                    flow += aug;
                    while (x != src)
                    {
                        x = pre[x];
                        cost[cur[x]] -= aug;
                        cost[cur[x] ^ 1] += aug;
                    }
                    aug = oo;
                }
                break;
            }
        }
        if (flag)
        {
            continue;
        }
        int tmp = n;
        for (int j = first[x]; j != -1; j = next[j])
        {
            y = v[j];
            if (cost[j] > 0 && dis[y] < tmp)
            {
                tmp = dis[y];
                cur[x] = j;
            }
        }
        if ((--gap[dis[x]]) == 0)
        {
            break;
        }
        gap[dis[x] = tmp + 1]++;
        x = pre[x];
    }
    return flow;
}
void out(vector<int> res)
{
    int i;
    sort(res.begin(), res.end());
    res.resize(unique(res.begin(), res.end()) - res.begin());
    for (i = 0; i < (int) res.size(); i++)
    {
        if (i)
        {
            putchar(' ');
        }
        printf("%d", res[i]);
    }
    putchar('\n');
}
void dfs(int x)
{
    int i;
    vis[x] = true;
    if (x == des)
    {
        flag = false;
    }
    for (i = first[x]; i != -1; i = next[i])
    {
        if (!vis[v[i]] && cost[i] > 0)
        {
            dfs(v[i]);
        }
    }
}
int main()
{
    int m;
    int i, j, k;
    int len;
    int ans;
    while (~scanf("%d%d", &m, &n))
    {
        src = 0;
        des = n + m + 1;
        e = 0;
        memset(first, -1, sizeof(first));
        gets(str);
        for (i = 1; i <= m; i++)
        {
            g[i].clear();
            gets(str);
            len = strlen(str);
            for (j = 0; j < len; j++)
            {
                for (; j < len && str[j] == ' '; j++);
                if (j < len)
                {
                    sscanf(str + j, "%d", &k);
                    g[i].push_back(k);
                }
                for (; j < len && isdigit(str[j]); j++)
                    ;
            }
        }
        for (i = 1; i <= n; i++)
        {
            scanf("%d", &a[i]);
            addEdge(m + i, des, a[i]);
        }
        ans = 0;
        for (i = 1; i <= m; i++)
        {
            addEdge(src, i, g[i][0]);
            ans += g[i][0];
            for (j = 1; j < (int) g[i].size(); j++)
            {
                addEdge(i, m + g[i][j], oo);
            }
        }
        n = des + 1;
        ans -= SAP();
        test.clear();
        app.clear();
        for (i = first[src]; i != -1; i = next[i])
        {
            k = v[i];
            flag = true;
            memset(vis, false, sizeof(vis));
            dfs(k);
            if (flag)
            {
                test.push_back(k);
                for (j = 1; j < (int) g[k].size(); j++)
                {
                    app.push_back(g[k][j]);
                }
            }
        }
        out(test);
        out(app);
        printf("%d\n", ans);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值