POJ 1275 Cashier Employment(差分約束系統)

來源:互聯網
上載者:User

摘自馮威論文——《數與圖的完美結合》

設num[ i ]為i時刻能夠開始工作的人數,x[ i ]為實際僱傭的人數,那麼x[ I ]<=num[ I ]。
設r[ i ]為i時刻至少需要工作的人數,於是有如下關係:
    x[ I-7 ]+x[ I-6 ]+x[ I-5 ]+x[ I-4
]+x[ I-3 ]+x[ I-2 ]+x[ I-1 ]+x[ I ]>=r[ I ]
設s[ I ]=x[ 1 ]+x[ 2 ]…+x[ I ],得到
    0<=s[ I ]-s[ I-1 ]<=num[ I ], 0<=I<=23
    s[ I ]-s[ I-8 ]>=r[ I ], 8<=I<=23
    s[ 23 ]+s[ I ]-s[ I+16 ]>=r[ I ], 0<=I<=7

    對於以上的幾組不等式,我們採用一種非常笨拙的辦法處理這一系列的不等式(其實也是讓零亂的式子變得更加整齊,易於處理)。首先我們要明白差分約束系統的應用對象(它通常針對多個二項相減的不等式的)於是我們將上面的所有式子都轉化成兩項未知項在左邊,另外的常數項在右邊,且中間用>=串連的式子,即:
    s[ I ]-s[ I-1 ]>=0
           (0<=I<=23)

    s[ I-1 ]-s[ I ]>=-num[ I ]
      (0<=I<=23)
    s[ I ]-s[ I-8 ]>=r[ I ]
        (8<=I<=23)
    s[ I ]-s[ I+16 ]>=r[ I ]-s[ 23 ]
 (0<=I<= 7)

 

論文有點小小的漏洞,也導致了它論文附帶的程式是錯誤的,有BUG

可行方案中還差一個約束條件

S[23] - S[-1] >= sum;sum為僱傭的出納員總數

 

將所有形如 A-B>=C 的式子 我們從節點B 引出一條有向邊指向A邊的權值為C  (這裡注意由於左右確定,式子又是統一的>=的不等式,所以A和B是相對確定的,邊是一定是指向A的) ,圖就建成了 。

在程式中,我用0作為上面說的-1來構圖

//差分約束系統(SPFA)<br />//對於差分約束系統,建立的不等式是>=則在SPFA中求最長路<br />//反之求最短路<br />//注意兩者對DIS初始化的不同<br />#include<iostream><br />#include<queue><br />#define INF 1000000000<br />using namespace std;<br />int r[25],t[25],caseN,n,T;<br />int head[25],V[700],next[700],W[700];<br />int cnt[25],dis[25];<br />bool inq[25];<br />int m;<br />inline void addEdge(int u,int v,int w)//新學的數組存放鄰接表的方式<br />{<br />V[m] = v;<br />W[m] = w;<br />next[m] = head[u];//head為表頭,調試後就能理解,這是倒著插的過程<br />head[u] = m++;<br />}<br />int SPFA(int ans)<br />{<br />memset(inq,0,sizeof(inq));//元素是否在隊列中<br />memset(cnt,0,sizeof(cnt));//記錄結點入隊列的次數<br />for(int i = 1;i <= 24;++i)dis[i] = -INF;<br />queue<int> q;<br />q.push(0);<br />inq[0] = 1;<br />dis[0] = 0;<br />cnt[0]++;<br />while(!q.empty())//SPFA+鄰接表模板<br />{<br />int u = q.front();q.pop();<br />inq[u] = 0;<br />for(int e = head[u];e != -1;e = next[e])<br />{<br />if(dis[u] + W[e] > dis[V[e]])<br />{<br />dis[V[e]] = dis[u] + W[e];<br />if(!inq[V[e]])<br />{<br />q.push(V[e]);<br />inq[V[e]] = 1;<br />if(++cnt[V[e]] > 24)return -1;//結點入度次數,如果超過|V|則說明存在迴路<br />}<br />}<br />}<br />}<br />if(dis[24] == ans)return 1;//如果不存在正權迴路且S[24]恰好等於ANS,則說明找到可行解,切ANS為最優解<br />else return 0;<br />}<br />void buildGraph(int ans)<br />{<br />m = 0;//重建立圖時,邊數記得回零<br />memset(head,-1,sizeof(head));<br />addEdge(0,24,ans);<br />for(int i = 1;i <= 24;++i)<br />{<br />addEdge(i - 1,i,0);<br />addEdge(i,i - 1,-t[i]);<br />}<br />for(int i = 1;i <= 8;++i)addEdge(i + 16,i,r[i] - ans);<br />for(int i = 9;i <= 24;++i)addEdge(i - 8,i,r[i]);<br />}<br />int main()<br />{<br />//freopen("in.txt","r",stdin);<br />scanf("%d",&caseN);<br />bool ok;<br />while(caseN--)<br />{<br />memset(t,0,sizeof(t));<br />ok = 0;<br />for(int i = 1;i <= 24;++i)scanf("%d",&r[i]);<br />scanf("%d",&n);<br />for(int i = 0;i < n;++i)<br />{<br />scanf("%d",&T);<br />t[T+1]++;<br />}<br />for(int ans = 0;ans <= n;++ans)<br />{<br />buildGraph(ans);<br />if(SPFA(ans) > 0)<br />{<br />printf("%d/n",ans);<br />ok = 1;<br />break;<br />}<br />}<br />if(!ok)printf("No Solution/n");<br />}<br />return 0;<br />} 

 


聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.