《浅谈图论模型的建立与应用》
2017-08-09 10:01
323 查看
图论的建模,就是要抓住问题的本质,把问题抽象为点、边、权的关系。
Place the Robots (ZOJ 1654)方案一:只关心空地与空地之间的联系,发生冲突的节点,连一条边,转换为求最大独立集。时间复杂度为:n*2^n
方案二:将所有横向方块,纵向方块分成X,Y部分,每个方块只能放一个机器人,那么有冲突的方块连一条边,问题转换为求最大匹配,最大匹配=最大流。
Source Code:
#include <cstdio> #include <vector> #include <queue> #include <cstring> #include <algorithm> #include <iostream> using namespace std; const int maxn = 1250; const int INF = 0x3f3f3f3f; int n,m; char maps[maxn][maxn]; int col[maxn][maxn],row[maxn][maxn]; int head[maxn*maxn]; struct Edge { int to; int next; } edges[maxn]; int cnt; void add(int u,int v) { edges[cnt].to = v; edges[cnt].next = head[u]; head[u] = cnt++; } bool vis[maxn]; int match[maxn]; bool dfs(int u) { for(int i=head[u];~i;i=edges[i].next) { int v = edges[i].to; if(!vis[v]) { vis[v] = 1; if(match[v]==-1||dfs(match[v])) { match[v] = u; return true; } } } return false; } int R,C; int solve() { int num = 0; memset(match,-1,sizeof(match)); for(int i=0;i<R;i++) { memset(vis,0,sizeof(vis)); if(dfs(i)) num++; } return num; } int main() { //freopen("in.txt","r",stdin); int t; scanf("%d",&t); for(int z=0; z<t; z++) { cnt = 0; scanf("%d%d",&n,&m); for(int i=0; i<n; i++) scanf("%s",maps[i]); R= 0,C=0; memset(col,0,sizeof(col)); memset(row,0,sizeof(row)); memset(head,-1,sizeof(head)); for(int i=0; i<n; i++) { for(int j=0; j<m; j++) { if(maps[i][j]=='o') { int tmp = j; while(tmp>=0) { if(maps[i][tmp]!='#') { row[i][tmp] = R; tmp--; } else break; } while(j<m) { if(maps[i][j]!='#') { row[i][j] = R; j++; } else break; } R++; } } } for(int j=0; j<m; j++) { for(int i=0; i<n; i++) { if(maps[i][j]=='o') { int tmp = i; while(tmp>=0) { if(maps[tmp][j]!='#') { col[tmp][j] = C; tmp--; } else break; } while(i<n) { if(maps[i][j]!='#') { col[i][j] = C; i++; } else break; } C++; } } } for(int i=0;i<n;i++) for(int j=0;j<m;j++) if(maps[i][j]=='o') add(row[i][j],col[i][j]); printf("Case :%d\n%d\n",z+1,solve()); } return 0; }
差分约束:
x_1-x_2<=b_1
x_2-x_3<=b_2
x_3-x_4<=b_3
x_4-x_5<=b_4
\to x_1-x_5<=4\tag{1}
如果存在负环:
x_5-x_1<=-5\tag{2}
(1)(2)相加
0<=-1\tag{3}
无解,在图上表示,及存在负环。
#include <bits/stdc++.h> using namespace std; const int maxn = 30; int r[maxn]; int t[maxn]; struct Edge { int from,to,dist; }; struct BellmanFord { int n,m; vector<Edge> edges; vector<int> G[maxn]; bool inq[maxn]; int d[maxn]; int p[maxn]; int cnt[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 dist) { edges.push_back((Edge){from,to,dist}); m = edges.size(); G[from].push_back(m-1); } bool negativeCycle() { queue<int> Q; memset(inq,0,sizeof(inq)); memset(cnt,0,sizeof(cnt)); for(int i=0;i<n;i++) { d[i] = 0; inq[0] = true; Q.push(i); } while(!Q.empty()) { int u = Q.front();Q.pop(); inq[u] = false; for(int i=0;i<G[u].size();i++) { Edge& e = edges[G[u][i]]; if(d[e.to]>d[u]+e.dist) { d[e.to] = d[u] + e.dist; p[e.to] = G[u][i]; if(!inq[e.to]) { Q.push(e.to); inq[e.to] = true; if(++cnt[e.to]>n) return true; } } } } return false; } }sol; void build(int ans) { sol.init(25); for(int i=1;i<=24;i++) { sol.addEdge(i-1,i,t[i]); sol.addEdge(i,i-1,0); } for(int i=8;i<=24;i++) sol.addEdge(i,i-8,-r[i]); for(int i=1;i<8;i++) sol.addEdge(i,24+i-8,ans-r[i]); sol.addEdge(24,0,-ans); } int main() { freopen("in.txt","r",stdin); int tt; scanf("%d",&tt); for(int z=0;z<tt;z++) { bool flag = false;; for (int i = 1; i <= 24; ++ i) scanf("%d", &r[i]); scanf("%d", &n); memset(t,0,sizeof(t)); int x; for(int i=0;i<n;i++) { scanf("%d",&x); x++; t[x]++; } int l= 0,r=n; int ans = -1; while(l<=r) { int mid = (l+r)>>1; build(mid); if(sol.negativeCycle()) { ans = mid; r = mid-1; } else l = mid+1; } printf("%d\n",ans); } return 0; }
本题的卡片总数有十万之多,而最终要选取的卡片数不超过100张。如果在构图之前,把没有用的卡片先删掉,必将大大提高效率。
什么样的卡片是没有用的呢?
先考虑第一种能力的选取:如果把全部卡片按第一种能力值从大到小排序,显然我们应该尽量从前面选A张出来,由于每张卡片只能使用一次,所以有可能会和其他的两种能力发生冲突,而冲突的卡片数最多是B+C张,所以实际上对我们有用的卡片只是前面的A+B+C张。
#include <bits/stdc++.h> using namespace std; const int maxn = 500, INF = 1000000000; struct Edge { int from, to, cap, flow, cost; }; struct MCMF { int n, m; vector<Edge> edges; vector<int> G[maxn]; bool inq[maxn]; // 是否在队列中 int d[maxn]; // Bellman-Ford 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.push_back((Edge) { from, to, cap, 0, cost }); edges.push_back((Edge) { to, from, 0, 0, -cost }); m = edges.size(); G[from].push_back(m-2); G[to].push_back(m-1); } bool BellmanFord(int s, int t, int &flow, long long& cost) { memset(inq,0,sizeof(inq)); for(int i=0; i<n; i++) d[i] = INF; d[s] = 0; inq[s] = true; p[s] = 0; a[s] = INF; queue<int> Q; Q.push(s); while(!Q.empty()) { int u = Q.front(); Q.pop(); inq[u] = false; for(int i = 0; i < 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] = true; } } } } if(d[t] == INF) return false; //s-t 不连通,失败退出 flow += a[t]; cost += (long long)d[t] * (long long)a[t]; int u = t; while(u != s) { edges[p[u]].flow += a[t]; edges[p[u]^1].flow -= a[t]; u = edges[p[u]].from; } return true; } pair<long long,int>Mincost(int s, int t) { long long cost = 0; int flow = 0; while(BellmanFord(s, t, flow, cost)); return pair<long long,int> {cost,flow}; } } sol; int a[100105],b[100105],c[100105],rk[100105]; int id[310]; bool cmpa(int i,int j) { if(a[i]==a[j])return a[i]+b[i]+c[i]>a[j]+b[j]+c[j]; return a[i]>a[j]; } bool cmpb(int i,int j) { if(b[i]==b[j])return a[i]+b[i]+c[i]>a[j]+b[j]+c[j]; return b[i]>b[j]; } bool cmpc(int i,int j) { if(c[i]==c[j])return a[i]+b[i]+c[i]>a[j]+b[j]+c[j]; return c[i]>c[j]; } int main() { // freopen("in.txt","r",stdin); int t; scanf("%d",&t); for(int i=0; i<t; i++) { int n; scanf("%d",&n); int A,B,C; scanf("%d%d%d",&A,&B,&C); for(int i=1; i<=n; i++) scanf("%d%d%d",&a[i],&b[i],&c[i]); for(int i=1; i<=n; i++)rk[i]=i; sort(rk+1,rk+1+n,cmpa); for(int i=1; i<=A+B+C; i++)id[i]=rk[i]; for(int i=1; i<=n; i++)rk[i]=i; sort(rk+1,rk+1+n,cmpb); for(int i=1; i<=A+B+C; i++)id[i+A+B+C]=rk[i]; for(int i=1; i<=n; i++)rk[i]=i; sort(rk+1,rk+1+n,cmpc); for(int i=1; i<=A+B+C; i++)id[i+2*(A+B+C)]=rk[i]; int m=3*(A+B+C); sort(id+1,id+1+m); m=unique(id+1,id+1+m)-id-1; sol.init(m+5); int s = 0; int p1 = m+1; int p2 = m+2; int p3 = m+3; int t = m+4; sol.AddEdge(s,p1,A,0); sol.AddEdge(s,p2,B,0); sol.AddEdge(s,p3,C,0); for(int i=1; i<=m; i++) { sol.AddEdge(p1,i,1,-a[id[i]]); sol.AddEdge(p2,i,1,-b[id[i]]); sol.AddEdge(p3,i,1,-c[id[i]]); } for(int i=1;i<=m;i++) sol.AddEdge(i,t,1,0); printf("%I64d ",-sol.Mincost(s,t).first); int k = 6*m+7; long long ans2 = 0; for(int i=1; i<=m; i++) { if(sol.edges[k].flow!=0) { ans2 += (a[id[i]]+b[id[i]]+c[id[i]]); } k+=2; } printf("%I64d\n",ans2); } return 0; }
相关文章推荐
- 建立django博客应用及数据库模型
- 测试设计002:有效测试用例设计,建立模型与应用技术很重要
- 微分方程在建模中的应用(建立差分模型)
- django中一个应用使用另一个应用的模型类并建立外键
- Android UI控件组合应用之一:建立数据模型
- Tomcat建立多个应用(Web Server),多个主机,多个站点的方法
- CS/CSS架构应用的软件性能测试模型分析
- 面向金融行业的电子商务应用框架模型
- 基于模型的可复用移动web应用程序开发-画出一个iPhone应用
- 建立可扩展的silverlight应用框架 step-2
- 领域模型驱动应用心得
- 数据库应用-半结构化数据模型1
- 初识yii Framework 框架 建立第一个 Yii 应用
- RNN,LSTM深度学习模型原理与应用
- SIFT算法的应用--目标识别之Bag-of-words模型
- 对象模型--策略、模式、应用 笔记1
- Ajax实践学习笔记(三) Ajax应用模型
- 《深入理解OSGi:Equinox原理、应用与最佳实践》笔记_2_建立开发环境
- 建立自己的3D模型文件
- 从头开始构建开源的Android应用研发ALM解决方案(二)建立个人桌面开发环境