- hdu 3572 Task Schedule 任务题
拆点(天)
题意:
现在你有m个机器,n个任务,每个任务有三个属性p,s,e,表示只能在[p,e]区间内花s的时间做完这个任务,一个机器一个时间只能做一个任务,一个任务一个时间只能被一个机器做,现在问你能不能完成全部的任务。
n,m <= 500
1 <= p,s,e <= 500
思路:
设0是源点,1~500是机器,501~1000是天数,1100是汇点,假设任务i三个属性p,s,e,源点连一条容量s的边到点 i,然后点 i 分别向每个[500+p, 500+e]的顶点连容量为1的边,最后501~1000向汇点连一条容量为1的边,跑个最大流,如果最大流等于所有任务s之和就是YES,否则就是NO。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 3000;
const int INF = 0x3f3f3f3f;
int tc,n,m;
struct Edge{
int from, to, cap, flow;
Edge(int u, int v, int c, int f)
: from(u), to(v), cap(c), flow(f) {}
};
struct Dicnic {
#define Type int
int n, m, s, t;
vector<Edge> edges;
vector<int> G[maxn];
bool vis[maxn];
Type d[maxn];
int cur[maxn];
void init(int n) {
this->n = n;
for (int i = 0; i <= n; ++i) G[i].clear();
edges.clear();
}
void addEdge(int from, int to, int cap) {
edges.emplace_back(Edge(from, to, cap, 0));
edges.emplace_back(Edge(to, from, 0, 0));
m = int(edges.size());
G[from].emplace_back(m-2);
G[to].emplace_back(m-1);
}
bool BFS() {
memset(vis, 0, sizeof(vis));
memset(d, 0, sizeof(d));
queue<int> q;
while (!q.empty()) q.pop();
q.push(s);
d[s] = 0;
vis[s] = 1;
while (!q.empty()) {
int x = q.front();
q.pop();
for (int i = 0; i < int(G[x].size()); ++i) {
Edge &e = edges[G[x][i]];
if (!vis[e.to] && e.cap > e.flow) {
vis[e.to] = 1;
d[e.to] = d[x] + 1;
q.push(e.to);
}
}
}
return vis[t];
}
Type DFS(int x, Type a) {
if (x == t || a == 0) return a;
Type flow = 0, f;
for (int &i = cur[x]; i < int(G[x].size()); ++i) {
Edge &e = edges[G[x][i]];
if (d[x]+1 == d[e.to] && (f = DFS(e.to, min(a, e.cap-e.flow))) > 0) {
e.flow += f;
edges[G[x][i]^1].flow -= f;
flow += f;
a -= f;
if (a == 0) break;
}
}
return flow;
}
Type Maxflow(int s, int t) {
this->s = s; this->t = t;
Type flow = 0;
while (BFS()) {
memset(cur, 0, sizeof(cur));
flow += DFS(s, INF);
}
return flow;
}
#undef Type
}dicnic;
int main() {
ios::sync_with_stdio(false);cin.tie(0);cout.precision(10);cout << fixed;
#ifdef LOCAL_DEFINE
freopen("input.txt", "r", stdin);
#endif
cin>>tc;
int kase=1;
while(tc--){
int sum=0;
cin>>n>>m;
dicnic.init(1300);
for(int i=1; i<=n; ++i){
int p,s,e;
cin>>p>>s>>e;
sum+=s;
dicnic.addEdge(0,i,s);
for(int j=500+p; j<=500+e; ++j) dicnic.addEdge(i,j,1);
}
for(int i=501; i<=1000; ++i) dicnic.addEdge(i,1100,m);
int all=dicnic.Maxflow(0,1100);
cout<<"Case "<<kase++<<": ";
if(all==sum) cout<<"Yes"<<'\n';
else cout<<"No"<<'\n';
}
#ifdef LOCAL_DEFINE
cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << " s.\n";
#endif
return 0;
}
- hdu 2732 Leapin’ Lizards 蜥蜴题
- 拆点(柱子)
题意:
给你一张图,上面有柱子和蜥蜴,有蜥蜴的地方一定有柱子,每根柱子还有耐久度,每个蜥蜴最多能跳到离原来位置<=d
距离的柱子,这个距离是x的距离差+
y的距离差。
思路:
因为柱子有耐久度,所以可拆点连一条有容量的边来表示他的限制。
设源点为s,入点为t。
如果p有蜥蜴,那么s到p连一条容量1的边。
如果p可以跳到安全地带,那么p+n*m到t连一条容量为INF的边。
接下来就是内部柱子里面乱跳了,4个for搞一下。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1100;
const int INF = 0x3f3f3f3f;
int tc, n, m, d, pi[40][40], cnt[40][40];
string a[40],b[40];
struct Edge{
int from, to, cap, flow;
Edge(int u, int v, int c, int f)
: from(u), to(v), cap(c), flow(f) {}
};
struct Dicnic {
#define Type int
int n, m, s, t;
vector<Edge> edges;
vector<int> G[maxn];
bool vis[maxn];
Type d[maxn];
int cur[maxn];
void init(int n) {
this->n = n;
for (int i = 0; i <= n; ++i) G[i].clear();
edges.clear();
}
void addEdge(int from, int to, int cap) {
edges.emplace_back(Edge(from, to, cap, 0));
edges.emplace_back(Edge(to, from, 0, 0));
m = int(edges.size());
G[from].emplace_back(m-2);
G[to].emplace_back(m-1);
}
bool BFS() {
memset(vis, 0, sizeof(vis));
memset(d, 0, sizeof(d));
queue<int> q;
while (!q.empty()) q.pop();
q.push(s);
d[s] = 0;
vis[s] = 1;
while (!q.empty()) {
int x = q.front();
q.pop();
for (int i = 0; i < int(G[x].size()); ++i) {
Edge &e = edges[G[x][i]];
if (!vis[e.to] && e.cap > e.flow) {
vis[e.to] = 1;
d[e.to] = d[x] + 1;
q.push(e.to);
}
}
}
return vis[t];
}
Type DFS(int x, Type a) {
if (x == t || a == 0) return a;
Type flow = 0, f;
for (int &i = cur[x]; i < int(G[x].size()); ++i) {
Edge &e = edges[G[x][i]];
if (d[x]+1 == d[e.to] && (f = DFS(e.to, min(a, e.cap-e.flow))) > 0) {
e.flow += f;
edges[G[x][i]^1].flow -= f;
flow += f;
a -= f;
if (a == 0) break;
}
}
return flow;
}
Type Maxflow(int s, int t) {
this->s = s; this->t = t;
Type flow = 0;
while (BFS()) {
memset(cur, 0, sizeof(cur));
flow += DFS(s, INF);
}
return flow;
}
#undef Type
}dicnic;
int myabs(int x) {return (x<0?-x:x);}
int getdist(int x1, int y1, int x2, int y2) {
int d1=myabs(x1-x2), d2=myabs(y1-y2);
return (d1+d2);
}
int main() {
ios::sync_with_stdio(false);cin.tie(0);cout.precision(10);cout << fixed;
#ifdef LOCAL_DEFINE
freopen("input.txt", "r", stdin);
#endif
int kase=1;
cin>>tc;
while(tc--){
dicnic.init(950);
cin>>n>>d;
for(int i=0; i<n; ++i) cin>>a[i];
for(int i=0; i<n; ++i) cin>>b[i];
m=int(a[0].size());
int tot=0;
memset(cnt,0,sizeof(cnt));
memset(pi,0,sizeof(pi));
for(int i=0; i<n; ++i){
for(int j=0; j<m; ++j){
int num=int(a[i][j]-'0');
pi[i][j]=num;
if(num!=0) {
cnt[i][j]=++tot;
dicnic.addEdge(cnt[i][j], cnt[i][j]+400, num);
}
}
}
for(int i=0; i<n; ++i){
for(int j=0; j<m; ++j){
if(cnt[i][j]==0) continue;
for(int ii=0; ii<n; ++ii){
for(int jj=0; jj<m; ++jj){
if(i==ii && j==jj) continue;
if(cnt[ii][jj]==0) continue;
if(getdist(i, j, ii, jj) <= d) {
dicnic.addEdge(cnt[i][j]+400, cnt[ii][jj], INF);
}
}
}
}
}
int sum=0;
for(int i=0; i<n; ++i){
for(int j=0; j<m; ++j){
if(b[i][j]=='L') {
++sum;
dicnic.addEdge(0, cnt[i][j], 1);
}
}
}
for(int i=0; i<n; ++i){
for(int j=0; j<m; ++j){
if(cnt[i][j]==0) continue;
int dis;
bool ok=false;
dis=i;
if(d>dis) ok=true;
dis=j;
if(d>dis) ok=true;
dis=n-1-i;
if(d>dis) ok=true;
dis=m-1-j;
if(d>dis) ok=true;
if(ok) {
dicnic.addEdge(cnt[i][j]+400, 900, INF);
}
}
}
int res=dicnic.Maxflow(0, 900);
if(sum-res>1) cout<<"Case #"<<kase++<<": "<<sum-res<<" lizards were left behind."<<'\n';
else if(sum-res==1) cout<<"Case #"<<kase++<<": "<<sum-res<<" lizard was left behind."<<'\n';
else cout<<"Case #"<<kase++<<": no lizard was left behind."<<'\n';
}
#ifdef LOCAL_DEFINE
cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << " s.\n";
#endif
return 0;
}
- hdu 2883 kebab 烤肉题(和任务题类似)
离散化
题意:
跟hdu 3572,也就是这个小结的第一题题意基本一样,就差了两点。
1.允许的时间变成了[s,e)而不是[s,e]。
2.s和e的范围变成了5000而不是500;
思路:
因为dicnic的上界复杂度是O(V^2*E)。你把5000个天全都拆出来肯定超时,因为只有200个时间段,所以可以离散化处理。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1100;
const int INF = 0x3f3f3f3f;
struct Edge{
int from, to, cap, flow;
Edge(int u, int v, int c, int f)
: from(u), to(v), cap(c), flow(f) {}
};
struct node{
int l,r;
node(){}
node(int _l, int _r):l(_l),r(_r){}
}nd[maxn];
int n,m,all[maxn],si[maxn],ni[maxn],ei[maxn],ti[maxn];
struct Dicnic {
#define Type int
int n, m, s, t;
vector<Edge> edges;
vector<int> G[maxn];
bool vis[maxn];
Type d[maxn];
int cur[maxn];
void init(int n) {
this->n = n;
for (int i = 0; i <= n; ++i) G[i].clear();
edges.clear();
}
void addEdge(int from, int to, int cap) {
edges.emplace_back(Edge(from, to, cap, 0));
edges.emplace_back(Edge(to, from, 0, 0));
m = int(edges.size());
G[from].emplace_back(m-2);
G[to].emplace_back(m-1);
}
bool BFS() {
memset(vis, 0, sizeof(vis));
memset(d, 0, sizeof(d));
queue<int> q;
while (!q.empty()) q.pop();
q.push(s);
d[s] = 0;
vis[s] = 1;
while (!q.empty()) {
int x = q.front();
q.pop();
for (int i = 0; i < int(G[x].size()); ++i) {
Edge &e = edges[G[x][i]];
if (!vis[e.to] && e.cap > e.flow) {
vis[e.to] = 1;
d[e.to] = d[x] + 1;
q.push(e.to);
}
}
}
return vis[t];
}
Type DFS(int x, Type a) {
if (x == t || a == 0) return a;
Type flow = 0, f;
for (int &i = cur[x]; i < int(G[x].size()); ++i) {
Edge &e = edges[G[x][i]];
if (d[x]+1 == d[e.to] && (f = DFS(e.to, min(a, e.cap-e.flow))) > 0) {
e.flow += f;
edges[G[x][i]^1].flow -= f;
flow += f;
a -= f;
if (a == 0) break;
}
}
return flow;
}
Type Maxflow(int s, int t) {
this->s = s; this->t = t;
Type flow = 0;
while (BFS()) {
memset(cur, 0, sizeof(cur));
flow += DFS(s, INF);
}
return flow;
}
#undef Type
}dicnic;
int main() {
ios::sync_with_stdio(false);cin.tie(0);cout.precision(10);cout << fixed;
#ifdef LOCAL_DEFINE
freopen("input.txt", "r", stdin);
#endif
while(cin>>n>>m){
dicnic.init(1050);
int tot=0, sum=0;
for(int i=1; i<=n; ++i){
cin>>si[i]>>ni[i]>>ei[i]>>ti[i];
sum+=ni[i]*ti[i];
dicnic.addEdge(0, i, ni[i]*ti[i]);
all[++tot]=si[i]; all[++tot]=ei[i];
nd[i]=node(si[i],ei[i]);
}
sort(all+1, all+1+tot);
for(int i=1; i<=n; ++i){
int ia=lower_bound(all+1, all+1+tot, nd[i].l)-all;
int ib=lower_bound(all+1, all+1+tot, nd[i].r)-all;
for(int j=ia; j<ib; ++j) dicnic.addEdge(i, 200+j, INF);
}
for(int i=1; i<tot; ++i){
int num=all[i+1]-all[i];
dicnic.addEdge(200+i, 1000, num*m);
}
int maxflow=dicnic.Maxflow(0, 1000);
if(maxflow==sum) cout<<"Yes"<<'\n';
else cout<<"No"<<'\n';
}
#ifdef LOCAL_DEFINE
cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << " s.\n";
#endif
return 0;
}
- hdu 1533 回家题
二分图最小匹配-> 二分图最大权匹配(KM+负边)或者 最小费用最大流(mcmf)
题意:
给你一个n*m的矩阵上面有m
和H
,m
代表人,H
代表房子,有相同数量的人和房子,现在问你让所有人都走到房子里的最小步数和是多少。
思路:
如果用mcmf做,设源点为s,汇点为t。
源点向每个m连一条容量为1,代价为0的流。
m向每个H连一条容量为1,代价为坐标绝对值差之和的流。
每个H向t连一条容量为1,代价为0的流。
然后跑mcmf,最小费用就是答案。
==============================================
用km做就更简单了,直接m和H之间连负边,然后跑km。
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = 1100;
const int INF = 0x3f3f3f3f;
int n, m, num[maxn][maxn];
char mat[maxn][maxn];
struct Edge{
int from, to, cap, flow, cost;
Edge(int u, int v, int c, int f, int cc)
: from(u), to(v), cap(c), flow(f), cost(cc) {}
};
struct MCMF {
int n, m;
vector<Edge> edges;
vector<int> G[maxn];
int inq[maxn];
int d[maxn];
int p[maxn];
int a[maxn];
void init(int n) {
this->n = n;
for (int i = 0; i <= n; ++i) G[i].clear();
edges.clear();
}
void addEdge(int from, int to, int cap, int cost) {
edges.emplace_back(Edge(from, to, cap, 0, cost));
edges.emplace_back(Edge(to, from, 0, 0, -cost));
m = int(edges.size());
G[from].emplace_back(m - 2);
G[to].emplace_back(m - 1);
}
bool spfa(int s, int t, int &flow, ll &cost) {
for (int i = 1; i <= n; ++i) d[i] = INF;
memset(inq, 0, sizeof(inq));
d[s] = 0;
inq[s] = 1;
p[s] = 0;
a[s] = INF;
queue<int> q;
q.push(s);
while (!q.empty()) {
int u = q.front();
q.pop();
inq[u] = 0;
for (int i = 0; i < int(G[u].size()); ++i) {
Edge &e = edges[G[u][i]];
if (e.cap > e.flow && d[e.to] > d[u] + e.cost) {
d[e.to] = d[u] + e.cost;
p[e.to] = G[u][i];
a[e.to] = min(a[u], e.cap - e.flow);
if (!inq[e.to]) {
q.push(e.to);
inq[e.to] = 1;
}
}
}
}
if (d[t] == INF) return false;
flow += a[t];
cost += (ll)d[t] * (ll)a[t];
for (int u = t; u != s; u = edges[p[u]].from) {
edges[p[u]].flow += a[t];
edges[p[u] ^ 1].flow -= a[t];
}
return true;
}
int MincostMaxflow(int s, int t, ll &cost) {
int flow = 0;
cost = 0;
while (spfa(s, t, flow, cost));
return flow;
}
}mcmf;
int myabs(int x) {return (x<0?-x:x);}
int getdist(int x1, int y1, int x2, int y2){
int ret=myabs(x1-x2)+myabs(y1-y2);
return ret;
}
int main() {
ios::sync_with_stdio(false);cin.tie(0);cout.precision(10);cout << fixed;
#ifdef LOCAL_DEFINE
freopen("input.txt", "r", stdin);
#endif
while(cin>>n>>m){
if(!n && !m) break;
mcmf.init(1050);
for(int i=0; i<=n; ++i) for(int j=1; j<=m; ++j) num[i][j]=0;
for(int i=1; i<=n; ++i) for(int j=1; j<=m; ++j) cin>>mat[i][j];
int tot=0;
for(int i=1; i<=n; ++i) for(int j=1; j<=m; ++j) if(mat[i][j]=='m') num[i][j]=++tot;
for(int i=1; i<=n; ++i) for(int j=1; j<=m; ++j) if(mat[i][j]=='H') num[i][j]=++tot;
for(int i=1; i<=n; ++i) {
for(int j=1; j<=m; ++j){
if(mat[i][j]=='m') mcmf.addEdge(0, num[i][j], 1, 0);
else if(mat[i][j]=='H') mcmf.addEdge(num[i][j], 1000, 1, 0);
}
}
for(int i=1; i<=n; ++i){
for(int j=1; j<=m; ++j){
if(mat[i][j]=='m') {
for(int ii=1; ii<=n; ++ii){
for(int jj=1; jj<=m; ++jj){
if(mat[ii][jj]=='H'){
mcmf.addEdge(num[i][j], num[ii][jj], 1, getdist(i, j, ii, jj));
}
}
}
}
}
}
ll cost=0;
ll maxflow=mcmf.MincostMaxflow(0, 1000, cost);
cout<<cost<<'\n';
}
#ifdef LOCAL_DEFINE
cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << " s.\n";
#endif
return 0;
}
- hdu 1565 方格取数 方格题
最大点权独立集 = 所有的点权 - 最小点权覆盖集(最小割)
题意:
现在有一个n*n的矩阵,里面每个格子都有一个非负数,现在规定取出来的数不能位置不能相邻,现在问你取出来数的值的最大和是多少。
思路:
最大点权独立集 = 所有的点权 - 最小点权覆盖集(最小割)
有点抽象,先记住再说。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1000;
const int INF = 0x3f3f3f3f;
int n, mat[maxn][maxn], num[maxn][maxn];
struct Edge{
int from, to, cap, flow;
Edge(int u, int v, int c, int f)
: from(u), to(v), cap(c), flow(f) {}
};
struct Dicnic {
#define Type int
int n, m, s, t;
vector<Edge> edges;
vector<int> G[maxn];
bool vis[maxn];
Type d[maxn];
int cur[maxn];
void init(int n) {
this->n = n;
for (int i = 0; i <= n; ++i) G[i].clear();
edges.clear();
}
void addEdge(int from, int to, int cap) {
edges.emplace_back(Edge(from, to, cap, 0));
edges.emplace_back(Edge(to, from, 0, 0));
m = int(edges.size());
G[from].emplace_back(m-2);
G[to].emplace_back(m-1);
}
bool BFS() {
memset(vis, 0, sizeof(vis));
memset(d, 0, sizeof(d));
queue<int> q;
while (!q.empty()) q.pop();
q.push(s);
d[s] = 0;
vis[s] = 1;
while (!q.empty()) {
int x = q.front();
q.pop();
for (int i = 0; i < int(G[x].size()); ++i) {
Edge &e = edges[G[x][i]];
if (!vis[e.to] && e.cap > e.flow) {
vis[e.to] = 1;
d[e.to] = d[x] + 1;
q.push(e.to);
}
}
}
return vis[t];
}
Type DFS(int x, Type a) {
if (x == t || a == 0) return a;
Type flow = 0, f;
for (int &i = cur[x]; i < int(G[x].size()); ++i) {
Edge &e = edges[G[x][i]];
if (d[x]+1 == d[e.to] && (f = DFS(e.to, min(a, e.cap-e.flow))) > 0) {
e.flow += f;
edges[G[x][i]^1].flow -= f;
flow += f;
a -= f;
if (a == 0) break;
}
}
return flow;
}
Type Maxflow(int s, int t) {
this->s = s; this->t = t;
Type flow = 0;
while (BFS()) {
memset(cur, 0, sizeof(cur));
flow += DFS(s, INF);
}
return flow;
}
#undef Type
}dicnic;
int main() {
ios::sync_with_stdio(false);cin.tie(0);cout.precision(10);cout << fixed;
#ifdef LOCAL_DEFINE
freopen("input.txt", "r", stdin);
#endif
while(cin>>n){
dicnic.init(600);
int tot=0, sum=0;
for(int i=1; i<=n; ++i){
for(int j=1; j<=n; ++j){
cin>>mat[i][j];
sum+=mat[i][j];
num[i][j]=++tot;
}
}
for(int i=1; i<=n; ++i){
for(int j=1; j<=n; ++j){
if((i+j)%2==0){
dicnic.addEdge(0, num[i][j], mat[i][j]);
if(i>1) dicnic.addEdge(num[i][j], num[i-1][j], INF);
if(i<n) dicnic.addEdge(num[i][j], num[i+1][j], INF);
if(j>1) dicnic.addEdge(num[i][j], num[i][j-1], INF);
if(j<n) dicnic.addEdge(num[i][j], num[i][j+1], INF);
} else{
dicnic.addEdge(num[i][j], 500, mat[i][j]);
}
}
}
cout<<sum-dicnic.Maxflow(0, 500)<<'\n';
}
#ifdef LOCAL_DEFINE
cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << " s.\n";
#endif
return 0;
}