题意:
数字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保存cap
void 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;
}
``
“`