HDU 4406

 金华网络赛1007题,拆边费用流。n天,m门课程,添加源汇s、t后很容易构图:s -> n个点连接流量为k,费用为0的边,n个点分别到m门课程根据01矩阵确定是否连边,每条边依然是流量为k,费用为0。最后就是m门课程到汇点t,如果课程基础分数base[i] < 60,则先连接一条边流量为60 - base[i],然后连接40条边(61 -- 100),每条边流量为1,费用为F(i) - F(i-1);否则,连接一些边(base[i]+1 -- 100),每条边流量为1,费用同样为F(i) - F(i-1),这里的拆边是重点。

       这种是我在比赛时的构图方法,但一直TLE,优化了很多地方始终都不能过!其实上面的构图方法是完全正确的,是 s -> 天数 -> 课程数 -> t 的模型,结果却是TLE,而只要将模型变为 s -> 课程数 -> 天数 -> t,结果是46ms AC!如果这是有专门数据卡构图方式,只能说出题者太高明了。。。。。

 

代码比赛时写的,只是后来换了构图模型,比较凌乱。

/****************************************************************
    Problem: HDU 4406
    User: Jeflie
    Language: C++
    Result: Accepted
    Time: 46 ms
    Memory: 336 kb
****************************************************************/
 
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
const int INF = 1e9;
const int N = 100;
 
struct Data
{
    int x, y, f, next;
    double w;
} edge[N*N];
int inx;
int node[N], path[N];
 
void addedge(int u, int v, int f, double w)
{
    //cout<<u<<" "<<v<<" "<<f<<" "<<w<<endl;
    edge[inx].x = u, edge[inx].y = v, edge[inx].f = f, edge[inx].w = w;
    edge[inx].next = node[u], node[u] = inx++;
    edge[inx].x = v, edge[inx].y = u, edge[inx].f = 0, edge[inx].w = -w;
    edge[inx].next = node[v], node[v] = inx++;
}
 
double dist[N];
int mark[N], que[N];
 
bool SPFA(int s, int e)
{
    for (int i = 0; i < N; i++)
        dist[i] = -1.0 * INF;
    memset(mark, 0, sizeof(mark));
    que[0] = s;
    int head = 1, tail = 0;
    dist[s] = 0;
    path[s] = -1;
    while ( head != tail )
    {
        int u = que[tail++];
        if (tail == N) tail = 0;
        mark[u] = 0;
        for (int ip = node[u]; ip != -1; ip = edge[ip].next)
        {
            Data &v = edge[ip];
            if (v.f > 0 && dist[u] + v.w > dist[v.y])
            {
                dist[v.y] = dist[u] + v.w;
                path[v.y] = ip;
                if (mark[v.y] == 0)
                {
                    mark[v.y] = 1;
                    que[head++] = v.y;
                    if (head == N) head = 0;
                }
            }
        }
    }
    return (dist[e] > 0);
}
 
void Fun(int s, int t)
{
    while ( SPFA(s, t) )
    {
        int Min = INF;
        for (int i = path[t]; i != -1; i = path[edge[i].x])
            Min = min(Min, edge[i].f);
        for (int i = path[t]; i != -1; i = path[edge[i].x])
        {
            edge[i].f -= Min;
            edge[i^1].f += Min;
        }
    }
}
 
int W[100], base[100];
int course[100][100];
 
int main()
{
    int n, k, m;
    while (scanf("%d %d %d", &n, &k, &m) != EOF)
    {
        if (n + k + m == 0) break;
        inx = 0;
        memset(node, -1, sizeof(node));
 
        for (int i = 1; i <= m; i++)
            scanf("%d", &W[i]);
        for (int i = 1; i <= m; i++)
            scanf("%d", &base[i]);
        for (int i = 1; i <= n; i++)
            for (int j = 1; j <= m; j++)
                scanf("%d", &course[i][j]);
 
        int s = 98, t = 99;
        for (int i = 1; i <= n; i++)
            addedge(i, t, k, 0);
        for (int i = 1; i <= n; i++)
        {
            for (int j = 1; j <= m; j++)
                if (course[i][j])
                    addedge(50+j, i, k, 0);
        }
        for (int i = 1; i <= m; i++)
        {
            double pre = 0;
            if (base[i] < 60)
            {
                addedge(s, 50+i, 60-base[i], 1.0*INF);
                pre = (4.0 - (3.0 * ((100-60)*(100-60))/1600)) * W[i];
                for (int j = 61; j <= 100; j++)
                {
                    double tmp = (4.0 - (3.0 * ((100-j)*(100-j))/1600)) * W[i];
                    addedge(s, 50+i, 1, tmp - pre);
                    pre = tmp;
                }
            }
            else
            {
                pre = (4.0 - (3.0 * ((100-base[i])*(100-base[i]))/1600)) * W[i];
                for (int j = base[i] + 1; j <= 100; j++)
                {
                    double tmp = (4.0 - (3.0 * ((100-j)*(100-j))/1600)) * W[i];
                    addedge(s, 50+i, 1, tmp - pre);
                    pre = tmp;
                }
            }
        }
        Fun(s, t);
 
        double ans = 0;
        int flag = 0;
        int add[100];
        memset(add, 0, sizeof(add));
        for (int ip = node[s]; ip != -1; ip = edge[ip].next)
            add[edge[ip].y-50] += edge[ip^1].f;
 
        int temp = 0;
        for (int i = 1; i <= m; i++)
        {
            temp += W[i];
            if (base[i] + add[i] < 60) flag = 1;
            ans += (4.0 - 3.0 * ((100-base[i]-add[i])*(100-base[i]-add[i])) / 1600) * W[i];
            //cout<<i<<" "<<base[i]<<" "<<add[i]<<endl;
        }
        ans /= temp;
 
        if (flag)
            printf("0.000000\n");
        else
            printf("%.6lf\n", ans);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值