【2012百度之星/资格赛】F:百科蝌蚪团
生活随笔
收集整理的這篇文章主要介紹了
【2012百度之星/资格赛】F:百科蝌蚪团
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
時間限制: 1000ms????? 內存限制: 65536kB
描述 輸入輸入有多組,每組測試數據以一個整數N開頭(1 ≤ N ≤ 50),表示蝌蚪團的成員數。緊接著,我們會有N個數據塊,每一個數據塊對應了一名蝌蚪團成員的日程情況。
每個數據塊以兩個整數開始,分別為K(1 ≤ K ≤ 50)和M(1 ≤ M ≤ 1440),用空格隔開。K表示這個數據塊對應蝌蚪團成員方便的時間段的數量,M表示這個成員愿意每天在百度百科工作的最長分鐘數。接下去的K行中,每行包括兩個時間,分別表示成“HH:MM”的格式,以空格分隔,分別對應了該蝌蚪團成員一個方便的時間段的開始時間、結束時間;例如09:00 10:00表明他在早上九點到十點的時間段是方便的,可以在百度百科工作。如果兩個時間相同,則說明這個他全天都是方便的。
最后一組數據的N為0,表示輸入結束。 輸出對于每組數據,輸出為一個整數,占一行。表示能保持24小時穩定在崗的蝌蚪團最少成員的數量。 樣例輸入 5
1 720
18:00 12:00
1 1080
00:00 23:00
1 1080
00:00 20:00
1 1050
06:00 00:00
1 360
18:00 00:00
3
1 540
00:00 00:00
3 480
08:00 10:00
09:00 12:00
13:00 19:00
1 420
17:00 00:00
3
1 1440
00:00 00:00
1 720
00:00 12:15
1 720
12:05 00:15
0 樣例輸出 2
1
1
轉載網上的思路:求最大流。? 題目中說守衛只能在整點或者整半點的時候交換工作,這是一個很明顯的暗示。
將每個守衛看成點,一天二十四個小時,分成48個點,如果一個守衛能在某半個小時連線,就將其與該半個小時的點連條線。
再添加一個源點,與每個守衛連線,權值就是守衛總共能工作的時間,添加一個匯點,與每半個小時連線。
這樣就是一個最大流問題,最大流有很多中解決方法,四天中有兩天就是為了調那個ISAP算法……
但是仔細想想,會出現一個問題:
假設時間點到匯點的權值無窮大,如果守衛一能在00:30和1:00工作,守衛二也能在00:30和1:00工作,那么守衛一和守衛二在同時在00:30和守衛在00:30,守衛二在1:00工作的最大流是一樣的,但題目要求使得一天二十四小時都有警衛工作。所以我們需要枚舉時間點到匯點的權值,做N次最大流。
另外還有一個需要注意的地方,源點到守衛點的權值要設為T/30,而守衛點到時間點的權值為1。為了這個我調了一個晚上……如果權值設為分鐘數,守衛點到時間點的權值為30的話,那么可能出現守衛在一個時間點工作小于30分鐘的情況。
#include<iostream> #include<cstdio> #include<algorithm> using namespace std; #include<memory.h>#define maxn 102 #define MAX 0xfffffff int d[maxn],g[maxn][maxn],f[maxn][maxn],pre[maxn],map[maxn][maxn],sum[maxn],current[maxn]; int n,m,num,mm; struct node {int x,y; }seg[1000],mytime[1000];int cmp(const node &a,const node &b) {return a.x<b.x; } void rev_bfs(int t) {int queue[maxn],flag[maxn];int head,tail,i;memset(sum,0,sizeof(sum));for (i=0;i<=n+49;++i){d[i]=n+49;sum[n+49]++;}sum[n+49]--;sum[0]++;d[t]=0;queue[1]=t;flag[t]=1;head=1;tail=1;memset(flag,0,sizeof(flag));while (head<=tail){for (i=0;i<=n+49;++i)if (flag[i]==0&&g[i][queue[head]]>0){queue[++tail]=i;d[i]=d[queue[head]]+1;sum[n+49]--;sum[d[i]]++;flag[i]=1;}head++;} } void augment(int s,int t) {int i,min;min=MAX;for (i=t;i!=s;i=pre[i])if (g[pre[i]][i]<min)min=g[pre[i]][i];for (i=t;i!=s;i=pre[i]){g[pre[i]][i]-=min;;g[i][pre[i]]+=min;f[pre[i]][i]+=min;f[i][pre[i]]-=min;} } int retreat(int *u,int s) {int v,min;min=n+49;for (v=0;v<=n+49;++v)if (g[*u][v]>0&&d[v]<min)min=d[v];sum[d[*u]]--;if ((sum[d[*u]])==0&&d[*u]<=n+49)return 0;d[*u]=min+1;sum[d[*u]]++;current[*u]=0;if (*u!=s)*u=pre[*u];return 1; } void ISAP(int s,int t) {int u,v;rev_bfs(t);u=s;while (d[s]<n+50){ for (v=current[u];v<=n+49;v++) if (g[u][v]>0&&d[u]==d[v]+1)break;if (v<=n+49){current[u]=v;pre[v]=u;u=v;if (u==t){augment(s,t);u=s;}}else if(retreat(&u,s)==0)return;} } void solve() {int i,j,a,b,c,d,min,t,k,ans,max,st,en,temp;while(scanf("%d",&n)!=EOF){if(!n) break;memset(map,0,sizeof(map));;for (i=1;i<=n;++i){scanf("%d %d",&m,&t);map[48][i+48]=t/30;num = mm = 0;for(j=1;j<=m;++j){scanf("%d:%d %d:%d",&a,&b,&c,&d);if (a==c && b==d){for (k=0;k<48;++k)map[i+48][k]=1;continue;}if (!c && !d){++num;seg[num].x=a*60+b , seg[num].y=1440;}else if (a*60+b>c*60+d){++num;seg[num].x=a*60+b , seg[num].y=1440;++num;seg[num].x=0 , seg[num].y=c*60+d;}else{++num;seg[num].x=a*60+b , seg[num].y=c*60+d;}}if(num==0)continue;sort(seg+1,seg+num+1,cmp);st=seg[1].x;en=seg[1].y;seg[num+1].x=1500;seg[num+1].y=1600;for (j=2;j<=num+1;++j){a=seg[j].x;b=seg[j].y;if (st<=a && a<=en&&en<b)en=b;else if(a>en){mm++;mytime[mm].x=st , mytime[mm].y=en;st=a;en=b;}}for (j=1;j<=mm;++j){a=mytime[j].x/60;b=mytime[j].x-60*a;c=mytime[j].y/60;d=mytime[j].y-60*c;if (a==c){if (b==0&&d>=30)map[i+48][a*2]=1;}else{if (b>0&&b<=30)b=30;if (b>30) {a++;b=0;}if (d<30)d=0;if (d>30)d=30;while (a!=c||b!=d){map[i+48][a*2+b/30]=1;b+=30;if (b==60){a++;b=0;}}}}}max=MAX;for (j=0;j<48;++j){temp=0;for (k=49;k<n+49;++k)if (map[k][j]>0)++temp;if (temp<max)max=temp;}ans=0;for (j=1;j<=max;++j){memset(g,0,sizeof(g));memset(f,0,sizeof(f));memset(current,0,sizeof(current));for (i=0;i<=49+n;++i)for (k=0;k<=49+n;++k)g[i][k]=map[i][k];for (i=0;i<48;++i)g[i][n+49]=j;ISAP(48,n+49);min=MAX;for (i=0;i<48;++i)if (f[i][n+49]<min)min=f[i][n+49];if (min>ans)ans=min;}printf("%d\n",ans);} } int main(void) {solve();return 0; }
百度百科有一支神奇的隊伍,他們叫自己“百科蝌蚪團”。為了更好的讓蝌蚪團的成員們安排工作,百度百科的運營團隊定出了一個24小時制的時間表。例如:
1.????每個蝌蚪團成員工作時長相同;
2.????必須安排蝌蚪團成員在他們方便的時間段工作;
3.????蝌蚪團成員安排時間最小安排時間節點(開始工作或停止工作)為半小時,比如04:00或04:30,而不是04:15;
4.????蝌蚪團成員一天在百度百科工作的時間是有上限的,他們會根據自己的情況給出上限。
5.????在特定時間段內必須有一定數量的蝌蚪團成員工作,以保證百度百科不斷的進步
請幫運營團隊計算一下,能保持24小時穩定在崗的蝌蚪團最少成員的數量。如果有2個蝌蚪團成員工作結束,同時另2個蝌蚪團成員開始工作,這段時間都算有2各成員穩定在崗。
每個數據塊以兩個整數開始,分別為K(1 ≤ K ≤ 50)和M(1 ≤ M ≤ 1440),用空格隔開。K表示這個數據塊對應蝌蚪團成員方便的時間段的數量,M表示這個成員愿意每天在百度百科工作的最長分鐘數。接下去的K行中,每行包括兩個時間,分別表示成“HH:MM”的格式,以空格分隔,分別對應了該蝌蚪團成員一個方便的時間段的開始時間、結束時間;例如09:00 10:00表明他在早上九點到十點的時間段是方便的,可以在百度百科工作。如果兩個時間相同,則說明這個他全天都是方便的。
最后一組數據的N為0,表示輸入結束。
將每個守衛看成點,一天二十四個小時,分成48個點,如果一個守衛能在某半個小時連線,就將其與該半個小時的點連條線。
再添加一個源點,與每個守衛連線,權值就是守衛總共能工作的時間,添加一個匯點,與每半個小時連線。
這樣就是一個最大流問題,最大流有很多中解決方法,四天中有兩天就是為了調那個ISAP算法……
但是仔細想想,會出現一個問題:
假設時間點到匯點的權值無窮大,如果守衛一能在00:30和1:00工作,守衛二也能在00:30和1:00工作,那么守衛一和守衛二在同時在00:30和守衛在00:30,守衛二在1:00工作的最大流是一樣的,但題目要求使得一天二十四小時都有警衛工作。所以我們需要枚舉時間點到匯點的權值,做N次最大流。
另外還有一個需要注意的地方,源點到守衛點的權值要設為T/30,而守衛點到時間點的權值為1。為了這個我調了一個晚上……如果權值設為分鐘數,守衛點到時間點的權值為30的話,那么可能出現守衛在一個時間點工作小于30分鐘的情況。
#include<iostream> #include<cstdio> #include<algorithm> using namespace std; #include<memory.h>#define maxn 102 #define MAX 0xfffffff int d[maxn],g[maxn][maxn],f[maxn][maxn],pre[maxn],map[maxn][maxn],sum[maxn],current[maxn]; int n,m,num,mm; struct node {int x,y; }seg[1000],mytime[1000];int cmp(const node &a,const node &b) {return a.x<b.x; } void rev_bfs(int t) {int queue[maxn],flag[maxn];int head,tail,i;memset(sum,0,sizeof(sum));for (i=0;i<=n+49;++i){d[i]=n+49;sum[n+49]++;}sum[n+49]--;sum[0]++;d[t]=0;queue[1]=t;flag[t]=1;head=1;tail=1;memset(flag,0,sizeof(flag));while (head<=tail){for (i=0;i<=n+49;++i)if (flag[i]==0&&g[i][queue[head]]>0){queue[++tail]=i;d[i]=d[queue[head]]+1;sum[n+49]--;sum[d[i]]++;flag[i]=1;}head++;} } void augment(int s,int t) {int i,min;min=MAX;for (i=t;i!=s;i=pre[i])if (g[pre[i]][i]<min)min=g[pre[i]][i];for (i=t;i!=s;i=pre[i]){g[pre[i]][i]-=min;;g[i][pre[i]]+=min;f[pre[i]][i]+=min;f[i][pre[i]]-=min;} } int retreat(int *u,int s) {int v,min;min=n+49;for (v=0;v<=n+49;++v)if (g[*u][v]>0&&d[v]<min)min=d[v];sum[d[*u]]--;if ((sum[d[*u]])==0&&d[*u]<=n+49)return 0;d[*u]=min+1;sum[d[*u]]++;current[*u]=0;if (*u!=s)*u=pre[*u];return 1; } void ISAP(int s,int t) {int u,v;rev_bfs(t);u=s;while (d[s]<n+50){ for (v=current[u];v<=n+49;v++) if (g[u][v]>0&&d[u]==d[v]+1)break;if (v<=n+49){current[u]=v;pre[v]=u;u=v;if (u==t){augment(s,t);u=s;}}else if(retreat(&u,s)==0)return;} } void solve() {int i,j,a,b,c,d,min,t,k,ans,max,st,en,temp;while(scanf("%d",&n)!=EOF){if(!n) break;memset(map,0,sizeof(map));;for (i=1;i<=n;++i){scanf("%d %d",&m,&t);map[48][i+48]=t/30;num = mm = 0;for(j=1;j<=m;++j){scanf("%d:%d %d:%d",&a,&b,&c,&d);if (a==c && b==d){for (k=0;k<48;++k)map[i+48][k]=1;continue;}if (!c && !d){++num;seg[num].x=a*60+b , seg[num].y=1440;}else if (a*60+b>c*60+d){++num;seg[num].x=a*60+b , seg[num].y=1440;++num;seg[num].x=0 , seg[num].y=c*60+d;}else{++num;seg[num].x=a*60+b , seg[num].y=c*60+d;}}if(num==0)continue;sort(seg+1,seg+num+1,cmp);st=seg[1].x;en=seg[1].y;seg[num+1].x=1500;seg[num+1].y=1600;for (j=2;j<=num+1;++j){a=seg[j].x;b=seg[j].y;if (st<=a && a<=en&&en<b)en=b;else if(a>en){mm++;mytime[mm].x=st , mytime[mm].y=en;st=a;en=b;}}for (j=1;j<=mm;++j){a=mytime[j].x/60;b=mytime[j].x-60*a;c=mytime[j].y/60;d=mytime[j].y-60*c;if (a==c){if (b==0&&d>=30)map[i+48][a*2]=1;}else{if (b>0&&b<=30)b=30;if (b>30) {a++;b=0;}if (d<30)d=0;if (d>30)d=30;while (a!=c||b!=d){map[i+48][a*2+b/30]=1;b+=30;if (b==60){a++;b=0;}}}}}max=MAX;for (j=0;j<48;++j){temp=0;for (k=49;k<n+49;++k)if (map[k][j]>0)++temp;if (temp<max)max=temp;}ans=0;for (j=1;j<=max;++j){memset(g,0,sizeof(g));memset(f,0,sizeof(f));memset(current,0,sizeof(current));for (i=0;i<=49+n;++i)for (k=0;k<=49+n;++k)g[i][k]=map[i][k];for (i=0;i<48;++i)g[i][n+49]=j;ISAP(48,n+49);min=MAX;for (i=0;i<48;++i)if (f[i][n+49]<min)min=f[i][n+49];if (min>ans)ans=min;}printf("%d\n",ans);} } int main(void) {solve();return 0; }
總結
以上是生活随笔為你收集整理的【2012百度之星/资格赛】F:百科蝌蚪团的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【2012百度之星/资格赛】E:C++
- 下一篇: 【2012百度之星/资格赛】H:用户请求