日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

差分约束 1:pku 1201 Intervals 2:pku 1364 King 3:hdu 1534

發(fā)布時間:2025/3/20 编程问答 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 差分约束 1:pku 1201 Intervals 2:pku 1364 King 3:hdu 1534 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

一個很好的差分約束總結(jié):http://972169909-qq-com.iteye.com/blog/1185527

第一:?
感覺難點在于建圖?
第二:?
①:對于差分不等式,a - b <= c ,建一條 b 到 a 的權(quán)值為 c 的邊,求的是最短路,得到的是最大值?
②:對于不等式 a - b >= c ,建一條 b 到 a 的權(quán)值為 c 的邊,求的是最長路,得到的是最小值?
③:存在負環(huán)的話是無解?
④:求不出最短路(dist[ ]沒有得到更新)的話是任意解?
第三:?
一種建圖方法:?
設(shè)x[i]是第i位置(或時刻)的值(跟所求值的屬性一樣),那么把x[i]看成數(shù)列,前n項和為s[n],則x[i] = s[i] - s[i-1];?
那么這樣就可以最起碼建立起類似這樣的一個關(guān)系:0 <= s[i] - s[i-1] <= 1;?
其他關(guān)系就要去題目探索了?

以上總結(jié)為轉(zhuǎn)載:

http://poj.org/problem?id=1201

題意是:給定n個閉區(qū)間,[ai,bi],求一個集合滿足他與每個集合相交的點數(shù)最少為ci,且擁有最少的元素個數(shù),輸出最少元素個數(shù);

首先根據(jù)1 <= ci <= bi - ai+1 的 s[bi + 1] - s[ai] >= ci; 然后根據(jù)0<=x[i]<= 1 得到 s[i] -s[i - 1] >= 0 s[i - 1] - s[i] >= -1; 由于會出現(xiàn)0點沒然后-1就無意思,于是我們轉(zhuǎn)化成

s[i +1] - s[i] >= 0 ?[i] ?- s[i ?+1] >= -1 求最長路徑得到最小值;

spfa實現(xiàn):

#include <cstdio> #include <cstring> #include <iostream> #include <queue> using namespace std;const int maxn = 50005; const int inf = 999999999; struct node {int v,w;int next; }e[maxn*5];int dis[maxn],ind[maxn],pre[5*maxn]; int cnt,n,mi,ma; bool inq[maxn];void init() {cnt = 0; mi = inf; ma = -inf;for (int i = 0; i < maxn; ++i){inq[i] = false;ind[i] = 0;pre[i] = -1;} } void addedge(int u,int v,int w) {e[cnt].v = v; e[cnt].w = w;e[cnt].next = pre[u];pre[u] = cnt++; } bool spfa(int u) {int i;for (i = mi; i <= ma; ++i) dis[i] = -inf;dis[u] = 0;queue<int>q;q.push(u); inq[u] = true;while (!q.empty()){int cur = q.front(); q.pop();if (++ind[cur] > n) return false;inq[cur] = false;for (i = pre[cur]; i != -1; i = e[i].next){int v = e[i].v; int w = e[i].w;if (dis[v] < dis[cur] + w){dis[v] = dis[cur] + w;if (!inq[v]){q.push(v);inq[v] = true;}}}}return true; } int main() {int i,a,b,c;init();scanf("%d",&n);for (i = 0; i < n; ++i){scanf("%d%d%d",&a,&b,&c);addedge(a,b + 1,c);mi = min(mi,a);ma = max(ma,b + 1);}for (i = mi; i <= ma; ++i){addedge(i,i + 1,0);addedge(i + 1,i,-1);}spfa(mi);printf("%d\n",dis[ma] - dis[mi]);return 0; }

  

?

  

?http://poj.org/problem?id=1364?

題意是有序列:?S = {a1, a2, ..., an}定義:Si = {aSi, aSi+1, ..., aSi+ni} ?Si > ki 或者 Si < ki

假設(shè)s[i] = a[1] + a[2] + ...... + a[i]; 則有si = s[si + ni] - s[si -1] ====> s[si + ni] - s[si - 1] >ki ? ?s[si + ni] - s[si - 1] < ki;由于差分約束的約束條件是<= >=?

轉(zhuǎn)化的 : s[si - 1] - s[si + ni] <= -ki - 1 ? s[si + ni] - s[si - 1] <= ki - 1 ? ? ? ? a-b <= c形式求最短路,判斷是否存在解即可:

注意:

1:由> ,< 到 <= ,>= 的轉(zhuǎn)化;

2:由于圖不一頂連通,即spfa()的啟點不確定,所以要建立超級源點:

#include <iostream> #include <cstring> #include <cstdio> #include <queue> using namespace std;const int maxn = 207; const int inf = 999999999;struct node {int w,v;int next; }e[maxn*maxn]; int pre[maxn*maxn],ind[maxn],dis[maxn]; int cnt,n,m; bool inq[maxn];void init() {cnt = 0;memset(e,0,sizeof(e));memset(ind,0,sizeof(ind));memset(pre,-1,sizeof(pre));memset(inq,false,sizeof(inq)); } void add(int u,int v,int w) {e[cnt].v = v; e[cnt].w = w;e[cnt].next = pre[u];pre[u] = cnt++; } bool spfa(int u) {int i;queue<int>q;for (i = 0; i < maxn; ++i) dis[i] = inf;dis[u] = 0;q.push(u); inq[u] = true;while (!q.empty()){int cur = q.front(); q.pop();if (++ind[cur] > n + 1) return false;//加入了超級源點故要大于n+1inq[cur] = false;for (i = pre[cur]; i != -1; i = e[i].next){int v = e[i].v, w = e[i].w;if (dis[v] > dis[cur] + w){dis[v] = dis[cur] + w;if (!inq[v]){inq[v] = true;q.push(v);}}}}return true; } int main() {int i,si,ni,ki;char op[5];while (~scanf("%d",&n)){if (!n) break; scanf("%d",&m);init();for (i = 0; i < m; ++i){scanf("%d%d%s%d",&si,&ni,op,&ki);if (op[0] == 'l')add(si - 1,si + ni,ki - 1);elseadd(si + ni,si - 1,-ki - 1);}for (i = 0; i <= n; ++i) add(n + 1,i,0);//建立超級源點bool mark = spfa(n + 1);if (mark) printf("lamentable kingdom\n");else printf("successful conspiracy\n");}return 0; }

  bellman_ford版本,由于它是對各邊進行松弛,所以多加入了0點不用對其加超級源點了。知識要進行n次而不是n-1次了。。

#include <iostream> #include <cstring> #include <cstdio> #include <queue> using namespace std;const int maxn = 207; const int inf = 999999999;struct node {int u,v,w; }e[maxn];int dis[maxn]; int n,m,cnt; void add(int u,int v,int w) {e[cnt].u = u;e[cnt].v = v;e[cnt].w = w;cnt++; } bool bellman_ford() {int i,j;for (i = 0; i <= n; ++i) dis[i] = inf;dis[0] = 0;bool flag;for (i = 0; i <= n; ++i){flag = true;for (j = 0; j < m; ++j){int u = e[j].u;int v = e[j].v;int w = e[j].w;if (dis[v] > dis[u] + w){dis[v] = dis[u] + w;flag = false;}}if (flag) break;}return flag; } int main() {int i,si,ni,ki;char op[4];while (~scanf("%d",&n)){if (!n) break; scanf("%d",&m);cnt = 0;for (i = 0; i < m; ++i){scanf("%d%d%s%d",&si,&ni,op,&ki);if (op[0] == 'g')add(si + ni,si - 1,-ki - 1);elseadd(si - 1,si + ni,ki - 1);}bool mark = bellman_ford();if (mark) printf("lamentable kingdom\n");else printf("successful conspiracy\n");}return 0; }

  

?http://acm.hdu.edu.cn/showproblem.php?pid=1534

題意:就是給你n個工程,每個工程必須在連續(xù)的V[i]時間內(nèi)完成,這些工程在完成順序上有四種形式的限制。

輸入形式為 *** a,b ?s[i]表示工程i的開始時間,v[i]表示必須花費連續(xù)v[i]的時間才能完成。由于是求最小值,所以化簡成 a - b >= c求最長路得最小值的形式;

FAS: b開始后a完成。 s[a] +v[a] >= s[b] -----> s[a] - s[b] >= -v[a]

FAF: b完成后a完成。 s[a] + v[a] >= s[b] + v[b]------> s[a] - s[b] >= v[b] - v[a];

SAF: b完成后a開始。 s[a] >= s[b] + v[b]-------> s[a] - s[b] >= v[b];

SAS: b開始后a開始。s[a] >= s[b]-------> s[a] - s[b] >= 0;

建圖,然后求解,得到的dis[i]就是每個項目在最短的時間消耗下的開始時間:

#include <cstring> #include <cstdio> #include <iostream> #include <queue> #define maxn 50004 using namespace std;struct node {int v,w;int next; }g[maxn]; int pre[maxn],ind[maxn],cnt; bool inq[maxn]; int n,V[maxn],dis[maxn]; const int inf = 99999999;void init() {cnt = 0;memset(g,0,sizeof(g));memset(pre,-1,sizeof(pre)); } void add(int u,int v,int w) {g[cnt].v = v;g[cnt].w = w;g[cnt].next = pre[u];pre[u] = cnt++; } bool spfa(int u) {int i;queue<int>q;for (i = 0; i <= n; ++i){dis[i] = -inf;inq[i] = false;ind[i] = 0;}dis[u] = 0;q.push(u); inq[u] = true;while (!q.empty()){int cur = q.front(); q.pop();if (++ind[cur] > n + 1) return false;for (i = pre[cur]; i != -1; i = g[i].next){int v = g[i].v, w = g[i].w;if (dis[v] < dis[cur] + w){dis[v] = dis[cur] + w;if (!inq[v]){q.push(v);inq[v] = true;}}}inq[cur] = false;}return true; } int main() {int i,cas = 1,a,b;while (~scanf("%d",&n)){if (!n) break;init();for (i = 1; i <= n; ++i) scanf("%d",&V[i]);char op[5];while (scanf("%s",op)){if (op[0] == '#') break;scanf("%d%d",&a,&b);if (!strcmp(op,"FAS")) add(b,a,-V[a]);else if (!strcmp(op,"FAF")) add(b,a,V[b] - V[a]);else if (!strcmp(op,"SAF")) add(b,a,V[b]);else add(b,a,0);}for (i = 1; i <= n; ++i) add(0,i,0);printf("Case %d:\n",cas++);bool mark = spfa(0);if (mark){for (i = 1; i <= n; ++i)printf("%d %d\n",i,dis[i]);}else{printf("impossible\n");}printf("\n");}return 0; }

  

?

總結(jié)

以上是生活随笔為你收集整理的差分约束 1:pku 1201 Intervals 2:pku 1364 King 3:hdu 1534的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。