URAL 1076:费用流解法

来源:互联网 发布:400÷1.25的简便算法 编辑:程序博客网 时间:2024/06/08 17:25

题意:
数字N表示有N个垃圾箱,而且刚好存在N类垃圾
每行输入的是第i个垃圾箱装有 x 数量 的第j类垃圾;
现在要你将这些垃圾分类,也就是把同类垃圾放在同一个垃圾箱里,
而且每个垃圾箱只能放一类垃圾。。。
每次把一个单元垃圾从一个垃圾箱移动到另一个垃圾箱就要1 effort;
求最小的 effort;

比赛时看数据开始以为dp能行,后来测试数据发现自己的状态转移方程是错的。。。
根本没有最优子结构;
比赛完后看题解,原来是 二分图的最佳匹配,
以前只会 最大匹配,,,然后看了一晚上,实在是难以理解
大家可以去看看
@wanggp3
http://www.cnblogs.com/wanggp3/p/3762568.html

最后实在不行了,突然发现好像最小费用流可以做。。。
只要自己建立 超级源,超级汇就可以了(常用套路)
1–N点 表示垃圾种类,N+1–N+N点 表示垃圾箱
每类垃圾 对 每个垃圾箱之间都存在边,容量为1,而费用就是
该类垃圾的总数-在该垃圾箱里已有的该类垃圾数量(sum[j] - map[i][j])

超级源点0 与 1–N 点(垃圾种类)都有边,容量为1, 费用为0;
超级汇点N+N+1 与 N+1–N+N点(垃圾箱)都有边,容量为1,费用为0;

然后计算,
最开始提交时超时了QAQ。。。以为费用流会超时。。。
后来网上看到有人说是可以用费用流做的,然后回来检查一下。。。
CHX 发现了 是在
for(int i=0; i

#include<iostream>#include<cstdio>#include<algorithm>#include<cstring>#include<vector>#include<queue>#include<cmath>using namespace std;const int INF = 1e9+9;const int MAXN = 350;struct Node{    int from;   //左    int to;     //右    int cap;    //容量    int flow;    //流量    int cost;    //费用};vector <Node> e;  ///一条边的所有属性vector <int> v[MAXN];   ///记录边的位置int vis[MAXN];int dis[MAXN];int father[MAXN],pos[MAXN];  ///father保存父节点, pos保存capvoid Clear(){   for(int i=0; i<=MAXN; ++i)      v[i].clear();   e.clear();}void add_Node(int from, int to, int cap, int cost){     e.push_back((Node){from,to,cap,0,cost});     e.push_back((Node){to,from,0,0,-cost});   ///反向边    int len = e.size()-1;    v[to].push_back(len);    v[from].push_back(len-1);}bool SPFA(int s, int t, int& flow, int& cost){      //memset(dis,0,sizeof(dis));     for(int i=0; i<MAXN; ++i)         dis[i] =  INF;     memset(vis,0,sizeof(vis));     dis[s] = 0;     ///最短路径,即 最小费用     vis[s] = 1;    ///标记是否在队列里     father[s] = 0;          pos[s] = INF;         queue<int> q;     q.push(s);   //  vector<int>::iterator it;     while(!q.empty())     {          int u = q.front();          q.pop();          vis[u] = 0;      //    for(it = v[u].begin();it!=v[u].end();it++)        //  {  //int i = it - v[u].end();       //         Node &tmp =  e[(*it)];        //  }          int s1 = v[u].size();          for(int i=0; i<s1; ++i)          {              Node &tmp = e[v[u][i]];                if(tmp.cap> tmp.flow && dis[tmp.to]>dis[u]+tmp.cost)              {                 dis[tmp.to] = dis[u] + tmp.cost;                 father[tmp.to] = v[u][i];        // (*it);                 pos[tmp.to] = min(pos[u], tmp.cap-tmp.flow);  ///更新边的剩余容量(最大流量),记录最小的                 if(!vis[tmp.to])                  {                     q.push(tmp.to);                     vis[tmp.to] = 1;                  }               }           }      }      if(dis[t]==INF) return false;      flow += pos[t];           cost += dis[t]*pos[t];      int t2 = t;     while(t2 != s)       {         e[father[t2]].flow += pos[t];           e[father[t2]^1].flow -= pos[t];           t2 = e[father[t2]].from;       }return true;}int Min_Cost(int s,int t){    int flow = 0;    int cost = 0;    while(SPFA(s,t,flow,cost));    return cost;}int all_trash[MAXN];int map1[MAXN][MAXN];int main(){    int N;    while(scanf("%d",&N)!=EOF)    {        Clear();        memset(all_trash,0,sizeof(all_trash));        int x;        for(int i=1; i<=N ;++i)          for(int j=1; j<=N; ++j)          {             scanf("%d",&map1[i][j]);             all_trash[j] += map1[i][j];          }        int u,v,w;        ///容量是1      for(int i=1; i<=N ;++i)        for(int j=1; j<=N; ++j)        {            //scanf("%d%d%d",&u,&v,&w);            u = i;            v = j+N;            w = all_trash[j] - map1[i][j];            add_Node(u,v,1,w);        //    add_Node(v,u,1,w);  ///双向边        }        for(int i=1; i<=N; ++i)             add_Node(0,i,1,0);        for(int j=N+1; j<=N+N; ++j)             add_Node(j,N+N+1,1,0);        printf("%d\n",Min_Cost(0,N+N+1));    }    return 0;}``

“`

0 0
原创粉丝点击