省赛练习2 Doctor NiGONiGO’s multi-core CPU 最大费用最大流

Doctor NiGONiGO’s multi-core CPU

Time Limit 2000ms

Memory Limit 65536K

description

Doctor NiGONiGO has developed a new kind of multi-core CPU, it works as follow. There are q (1 < q ≤ 50) identical cores in the CPU, and there are p (0 < p ≤ 200) jobs need to be done. Each job should run in some core and need only one unit time. The cores in the CPU can work simultaneously but each core can implement only one job at a time. When a job completed, it will incur a deferral cost. Job i has a deferral cost c(i, j) (0 ≤ c(i, j) ≤ 1000000), where j is the completion time of the job (1 ≤ j ≤ p) because any job done in the time later than p obviously not the optimal solution). Here we assume that c(i, j) is a monotonically no decreasing function of j. Now you are asked to find the schedule which have the minimum overall deferral cost.
							

input

An integer T indicated the number of test cases. 
For each test case:
There are two integers q, p in first line. 
And Following is p lines, each line contain p integer, the jth integer of the ith line is the deferral cost c(i, j).
							

output

For each test case, output a singer integer, which is the minimum total deferral cost of the Problem.
							

sample_input

1
2 4
89 145 181 269
4 86 158 164
60 143 157 165
4 45 109 207
							

sample_output

254
------------------------------------------------------------------------------------------------------------

源点S到工作Pi连一条容量为1费用为0的边,工作Pi到时间Tj连一条容量为1费用为c(i,j)的边,时间Tj到汇点连一条容量为q费用为0的边。

最大费用最大流即是答案。

由于同一件工作的花费是递增的,所以至多用(p/q+1)时间就可以完成所有工作,因此时间(p/q+1)之后的边可以删去。

------------------------------------------------------------------------------------------------------------

#include <iostream>
#include <cstdio>

using namespace std;

const int OO=1e9;//无穷大
const int maxm=11111111;//边的最大数量,为原图的两倍
const int maxn=222222;//点的最大数量

int node,src,dest,edge;//node节点数,src源点,dest汇点,edge边数
int head[maxn],p[maxn],dis[maxn],q[maxn],vis[maxn];//head链表头,p记录可行流上节点对应的反向边,dis计算距离

struct edgenode
{
    int to;//边的指向
    int flow;//边的容量
    int cost;//边的费用
    int next;//链表的下一条边
} edges[maxm];

void prepare(int _node,int _src,int _dest);
void addedge(int u,int v,int f,int c);
bool spfa();

inline int min(int a,int b)
{
    return a<b?a:b;
}

inline void prepare(int _node,int _src,int _dest)
{
    node=_node;
    src=_src;
    dest=_dest;
    for (int i=0; i<node; i++)
    {
        head[i]=-1;
        vis[i]=false;
    }
    edge=0;
}

void addedge(int u,int v,int f,int c)
{
    edges[edge].flow=f;
    edges[edge].cost=c;
    edges[edge].to=v;
    edges[edge].next=head[u];
    head[u]=edge++;
    edges[edge].flow=0;
    edges[edge].cost=-c;
    edges[edge].to=u;
    edges[edge].next=head[v];
    head[v]=edge++;
}

bool spfa()
{
    int i,u,v,l,r=0,tmp;
    for (i=0; i<node; i++) dis[i]=OO;
    dis[q[r++]=src]=0;
    p[src]=p[dest]=-1;
    for (l=0; l!=r; ((++l>=maxn)?l=0:1))
    {
        for (i=head[u=q[l]],vis[u]=false; i!=-1; i=edges[i].next)
        {
            if (edges[i].flow&&dis[v=edges[i].to]>(tmp=dis[u]+edges[i].cost))
            {
                dis[v]=tmp;
                p[v]=i^1;
                if (vis[v]) continue;
                vis[q[r++]=v]=true;
                if (r>=maxn) r=0;
            }
        }
    }
    return p[dest]>=0;
}

int spfaflow()
{
    int i,ret=0,delta;
    while (spfa())
    {
        //按记录原路返回求流量

        for (i=p[dest],delta=OO; i>=0; i=p[edges[i].to])
        {
            delta=min(delta,edges[i^1].flow);
        }
        for (int i=p[dest]; i>=0; i=p[edges[i].to])
        {
            edges[i].flow+=delta;
            edges[i^1].flow-=delta;
        }
        ret+=delta*dis[dest];
    }
    return ret;
}

int q_cpu;
int p_jobs;
int cost[222][222];
int T;
int ls;

int main()
{
    scanf("%d",&T);
    while (T--)
    {
        scanf("%d%d",&q_cpu,&p_jobs);
        ls=p_jobs/q_cpu+1;
        prepare(p_jobs*2+2,0,p_jobs*2+1);
        for (int i=1;i<=p_jobs;i++)
        {
            addedge(src,i,1,0);
            for (int j=1;j<=p_jobs;j++)
            {
                scanf("%d",&cost[i][j]);
                if (j<=ls) addedge(i,j+p_jobs,1,cost[i][j]);
            }
        }
        for (int i=1;i<=p_jobs;i++)
        {
            if (i<=ls) addedge(i+p_jobs,dest,q_cpu,0);
        }
        int ans=spfaflow();
        printf("%d\n",ans);
    }
    return 0;
}







  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值