poj 3469 双核cpu  最小割最大流

题目 http://poj.org/problem?id=3469

 

题目大意:有两个cpu, 给定n个任务要在某个cpu上运行,给出n个任务分别在两个cpu上运行的消耗a[i],b[i]; 并且给定m个关系。

关系pq, c是指如果任务pq不在同一个cpu上运行,则需要额外的消耗c。如果有两个任务同时在听一个cpu运行,则额外消耗不计。

 

考查点:最小割

 

思路:读完题以后,就感觉像是网络流的题,感觉两个cpu正好像天然的源点和汇点,用第一个cpu向每个任务连一条流量为a[i]的边,表示第i个任务在cpu-1上运行的消耗。从每个任务向第二个cpu连一条流量为b[i]的边,表示任务icpu-2上运行消耗的时间,那么一个割的含义就是把任务i分配到某个cpu上运行。但是,第二个条件控制?如何增加两个关联的任务不在同一个cpu上运行的额外消耗?经过漫长的思考,最后发现只要在pq之间加一条流量为c双向边,这样单纯的割cpu与任务之间的流就不能把任务割掉了。这样就实现了第二个条件。因此,见图的思路就清晰了,算法方面,由于此图可能层次明显,故用dinic算法。

此外此题是测速度的题

 

提交情况  Accepted  1

收获 :对建图有了更深的认识,对dinic的当前狐优化有了更好的

认识

 

经验:要把每条流的含义搞清楚

 

AC  code

#include <stdio.h>

#include <string.h>

#define MAXN 21000

#define MAXM 10000000

#define INF 2100000000

 

int to[MAXM], flux[MAXM], next[MAXM], point[MAXN];

int vis[MAXN], d[MAXN], cur[MAXN];

int ad, n;

 

int bfs(int s, int t){

      int queue[MAXN], b[MAXN];

      int head = 0, tail = 1;

      int u, v, p;

      memset(d, -1, sizeof(d));

      queue[head] = s;

      d[s] = 0;

      while(head < tail){

            u = queue[head ++];

            for(p = point[u]; ~p; p = next[p]){

                  v = to[p];

                  if(flux[p] && d[v] == -1){

                        d[v] = d[u] + 1;

                        queue[tail ++] = v;

                        if(d[t] > 0) return 1;

                  }

            }

      }

      return (d[t] > 0);

}

 

int dfs(int x, int low){

      if(x == n + 1) return low;

      vis[x] = 1;

      for(int p = cur[x], temp, v; ~ p; p = next[p], cur[x] = p){

            v = to[p];

            if(!vis[v] && flux[p] && d[x] == d[v] - 1)

                  if(temp = dfs(v, low < flux[p] ? low : flux[p])){

                        flux[p] -= temp;

                        flux[p ^ 1] += temp;

                        return temp;

                  }

      }

      return 0;

}

 

 

int main(){

      int m, i;

      int x, y , z;

      int ans, flow;

      while(~scanf("%d %d", &n, &m)){

            ans = 0;

            memset(point , -1, sizeof(point));

            ad = 0;

            for(i = 1; i <= n; i ++){

                  scanf("%d %d", &x, &y);

                  to[ad] = i; flux[ad] = x; next[ad] = point[0]; point[0] = ad ++;

                  to[ad] = 0; flux[ad] = 0; next[ad] = point[i]; point[i] = ad ++;

                  to[ad] = n + 1; flux[ad] = y; next[ad] = point[i]; point[i] =ad ++;

                  to[ad] = i; flux[ad] = 0; next[ad] = point[n + 1]; point[n + 1] = ad ++;

            }

            while(m --){

                  scanf("%d %d %d", &x, &y, &z);

                  to[ad] = y; flux[ad] = z; next[ad] = point[x]; point[x] = ad ++;

                  to[ad] = x; flux[ad] = z; next[ad] = point[y]; point[y] = ad ++;

            }

            while(bfs(0, n + 1)){

                  for(i = 0; i <= n + 1; i ++) cur[i] = point[i];

                  while(1){

                        memset(vis, 0, sizeof(vis));

                        if((flow = dfs(0, INF)) == 0) break;

                        ans += flow;

                  }

            }

            printf("%d\n", ans);

      }

      return 0;

}

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值