無法拯救我的菜----焦作網路賽 F. Modular Production Line
阿新 • • 發佈:2018-12-11
poj3680原題,資料都一樣,是最小費用最大流摸板題 轉載:https://blog.csdn.net/zhou_yujia/article/details/52411251 先看一下poj3680: 離散化所有區間的端點,把每個端點看做一個頂點,建立附加源S匯T。 1、從S到頂點1(最左邊頂點)連線一條容量為K,費用為0的有向邊。 2、從頂點2N(最右邊頂點)到T連線一條容量為K,費用為0的有向邊。 3、從頂點i到頂點i+1(i+1<=2N),連線一條容量為無窮大,費用為0的有向邊。 4、對於每個區間[a,b],從a對應的頂點i到b對應的頂點j連線一條容量為1,費用為區間長度的有向邊。 求最大費用最大流,最大費用流值就是最長k可重區間集的長度。 這個問題可以看做是求K條權之和最大的不想交路徑,每條路徑為一些不相交的區間序列。由於是最大費用流,兩條路徑之間一定有一些區間相交,可以看做事相交部分重複了2次, 而K條路經就是最多重複了K次。最簡單的想法就是把區間排序後,不相交的區間之間連線一條邊,由於每個區間只能用一次,所以要拆點,點內限制流量
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<map> #include<vector> #include<queue> using namespace std; const int inf = 0x3f3f3f3f; const int MAXN = 405; const int MAXM = 100005; typedef struct Node{ int s,to,next,capacity,value; }Node; int n,k; int ecnt; Node node[MAXM]; int pre[MAXN]; int head[MAXN]; int dis[MAXN]; bool vis[MAXN]; int u[MAXN],v[MAXN],w[MAXN]; vector<int>ve; map<int,int>mp; void init() { ecnt = 0; memset(head,-1,sizeof(head)); memset(node,0,sizeof(node)); } void addEdge(int u,int v,int w,int c) { node[ecnt].to = v; node[ecnt].s = u; node[ecnt].capacity = c;//流量 node[ecnt].value = w;//路徑長度是費用 node[ecnt].next = head[u]; head[u] = ecnt++; node[ecnt].to = u; node[ecnt].s = v; node[ecnt].capacity = 0;//流量 node[ecnt].value = -w;//路徑長度是費用 node[ecnt].next = head[v]; head[v] = ecnt++; } bool spfa(int s,int t,int nnum) { memset(vis,0,sizeof(vis)); memset(pre,-1,sizeof(pre)); for(int i = 0;i <= nnum;++i) { dis[i] = inf; } queue<int>que; que.push(s); dis[s] = 0; vis[s] = true; while(!que.empty()) { int temp = que.front(); que.pop(); vis[temp] = false; for(int i = head[temp];i + 1;i = node[i].next) { if(node[i].capacity) { int ne = node[i].to; if(dis[temp] + node[i].value < dis[ne]){ dis[ne] = dis[temp] + node[i].value; pre[ne] = i; if(!vis[ne]){ que.push(ne); vis[ne] = true; } } } } // for(int i = 0;i <= nnum;++i) // cout << dis[i] << " "; // cout << endl; } if(dis[t] == inf) return false; return true; } int getMincost(int s,int t,int nnum) { int ans_flow = 0; int ans_cost = 0; int temp,minc; while(spfa(s,t,nnum)) { // cout << 0 << endl; temp = t; minc = inf; while(pre[temp] != -1) { minc = min(node[pre[temp]].capacity,minc); temp = node[pre[temp]].s; } temp = t; while(pre[temp] != -1) { node[pre[temp]].capacity -= minc; int ss = pre[temp] ^ 1; node[ss].capacity += minc; temp = node[pre[temp]].s; } //cout << dis[t] << " " << minc << endl; // for(int i = s;i <= t;++i) // { // cout << dis[i] << " "; // } // cout << endl; ans_cost += dis[t] * minc; } return ans_cost; } int main() { int t; scanf("%d",&t); while(t--) { mp.clear();ve.clear(); init(); scanf("%d %d",&n,&k); for(int i = 1;i <= n;++i) { scanf("%d %d %d",&u[i],&v[i],&w[i]); ve.push_back(u[i]); ve.push_back(v[i]); } sort(ve.begin(),ve.end()); ve.erase(unique(ve.begin(),ve.end()),ve.end()); int s = 0; int t = ve.size() + 1; int len = ve.size(); for(int i = 0;i < len;++i) mp[ve[i]] = i + 1; addEdge(s,1,0,k); addEdge(ve.size(),t,0,k); for(int i = 1;i < len;++i) addEdge(i,i + 1,0,inf); for(int i = 1;i <= n;++i) addEdge(mp[u[i]],mp[v[i]],-w[i],1); int res = getMincost(s,t,t); printf("%d\n",-1 * res); } return 0; }
再看F這道題,區間變了而已,改為把A[i] - 1 放入陣列即可 注意:為什麼建邊把權值變為負呢,模板是最小費用最大流,每次用spfa找增廣路徑時,找到的是最小權值和,題意應該是找最大權值和
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<map> #include<vector> #include<queue> using namespace std; const int inf = 0x3f3f3f3f; const int MAXN = 405; const int MAXM = 100005; typedef struct Node{ int s,to,next,capacity,value; }Node; int n,k,m; int ecnt; Node node[MAXM]; int pre[MAXN]; int head[MAXN]; int dis[MAXN]; bool vis[MAXN]; int u[MAXN],v[MAXN],w[MAXN]; vector<int>ve; map<int,int>mp; void init() { ecnt = 0; memset(head,-1,sizeof(head)); memset(node,0,sizeof(node)); } void addEdge(int u,int v,int w,int c) { node[ecnt].to = v; node[ecnt].s = u; node[ecnt].capacity = c;//流量 node[ecnt].value = w;//路徑長度是費用 node[ecnt].next = head[u]; head[u] = ecnt++; node[ecnt].to = u; node[ecnt].s = v; node[ecnt].capacity = 0;//流量 node[ecnt].value = -w;//路徑長度是費用 node[ecnt].next = head[v]; head[v] = ecnt++; } bool spfa(int s,int t,int nnum) { memset(vis,0,sizeof(vis)); memset(pre,-1,sizeof(pre)); for(int i = 0;i <= nnum;++i) { dis[i] = inf; } queue<int>que; que.push(s); dis[s] = 0; vis[s] = true; while(!que.empty()) { int temp = que.front(); que.pop(); vis[temp] = false; for(int i = head[temp];i + 1;i = node[i].next) { if(node[i].capacity) { int ne = node[i].to; if(dis[temp] + node[i].value < dis[ne]){ dis[ne] = dis[temp] + node[i].value; pre[ne] = i; if(!vis[ne]){ que.push(ne); vis[ne] = true; } } } } // for(int i = 0;i <= nnum;++i) // cout << dis[i] << " "; // cout << endl; } if(dis[t] == inf) return false; return true; } int getMincost(int s,int t,int nnum) { int ans_flow = 0; int ans_cost = 0; int temp,minc; while(spfa(s,t,nnum)) { // cout << 0 << endl; temp = t; minc = inf; while(pre[temp] != -1) { minc = min(node[pre[temp]].capacity,minc); temp = node[pre[temp]].s; } temp = t; while(pre[temp] != -1) { node[pre[temp]].capacity -= minc; int ss = pre[temp] ^ 1; node[ss].capacity += minc; temp = node[pre[temp]].s; } //cout << dis[t] << " " << minc << endl; // for(int i = s;i <= t;++i) // { // cout << dis[i] << " "; // } // cout << endl; ans_cost += dis[t] * minc; } return ans_cost; } int main() { int t; scanf("%d",&t); while(t--) { mp.clear();ve.clear(); init(); scanf("%d %d %d",&m,&k,&n); for(int i = 1;i <= n;++i) { scanf("%d %d %d",&u[i],&v[i],&w[i]); ve.push_back(u[i] - 1); ve.push_back(v[i]); } sort(ve.begin(),ve.end()); ve.erase(unique(ve.begin(),ve.end()),ve.end()); int s = 0; int t = ve.size() + 1; int len = ve.size(); for(int i = 0;i < len;++i) mp[ve[i]] = i + 1; addEdge(s,1,0,k); addEdge(ve.size(),t,0,k); for(int i = 1;i < len;++i) addEdge(i,i + 1,0,inf); for(int i = 1;i <= n;++i) addEdge(mp[u[i] - 1],mp[v[i]],-w[i],1); int res = getMincost(s,t,t); printf("%d\n",-1 * res); } return 0; }