【BZOJ 3661】 Hungry Rabbit (贪心、优先队列)

3661: Hungry Rabbit

Time Limit: 100 Sec  Memory Limit: 512 MBSec  Special Judge
Submit: 67  Solved: 47

Description

可怕的洪水在夏天不期而至,兔子王国遭遇了前所未有的饥荒,它们不得不去外面的森林里寻找食物。
为了简化起见,我们假设兔子王国中有n只兔子,编号为1n。在救济粮到来之前的m天中,每天恰好有k只兔子需要去森林里寻找粮食。森林里居住着可怕的大灰狼,所幸兔子已经摸清了大灰狼捕食习惯,即狼们在每一天只会捕食特定编号的兔子。为了安全起见,兔子们需要保证每次出去觅食的k只兔子都不会被狼捕食。由于每天出去捕食的兔子都不尽相同,它们为每一天定义了一个生疏度pi,即第i天出来寻找食物,但是第i1天却没有出来觅食的兔子个数。规定第1天的生疏度为0.现在兔子们希望在保证安全的前提下,每天的生疏度不能超过L,请为兔子们构造一个合法的方案。

Input

第一行包括四个整数n,m,k和L.
接下来n行,每行一个长度为m的01串。其中第i行第j个字符若为0,则表示狼在第j天会捕食编号为i的兔子,为1则表示不捕食。

Output

m行,每行k个1-n之间互不相同的整数,代表这一天出去寻找食物的兔子编号。如果没有合法方案,则输出一行1即可。

Sample Input

5 4 3 1
1001
1101
1111
1110
0111

Sample Output

2 3 4
2 3 4
3 4 5
2 3 5

HINT

对于 100% 的测试数据,1 <= n;m <= 800; 1 <= k <= n; 1 <= l <= k

Source

 
【分析】
  
  唉、、、我打了网络流,70分。。。【其实数据弱恰好我数组开小本来90分的。。
  说说我的网络流打法吧,毕竟想了很久。
  就是1100011的兔子可以看成两只1100000、0000011的兔子。
  然后就是说每个兔子表示一个区间,表示它可以从l~r这几天工作。
  就是要找若干个区间覆盖全区间k次。
  就类似这样子的建图:
  
  拆点那里的点容限制了<=L次交换。反向INF表示区间相交求并集。然后判断是否满流就是否有解。
  然后有意义的表示区间的边就是答案,输出即可。【好像输出答案有点困难啊??
 
  然后正解是贪心!【表示考场上想过不知道为什么脑抽觉得n^2log过不了???【黑人问号???
  就是每次贪心找尽量长的区间。。。
  有优先队列维护,每次用最优的更新最差的看看是否成立即可。
 
 1 #include<cstdio>
 2 #include<cstdlib>
 3 #include<cstring>
 4 #include<iostream>
 5 #include<algorithm>
 6 #include<queue>
 7 using namespace std;
 8 #define Maxn 810
 9 #define INF 0xfffffff
10 
11 struct node
12 {
13     int l,r,id;
14 }t[Maxn*Maxn];
15 struct cmp{bool operator()(node x,node y){return x.r<y.r;}};
16 struct cmp2{bool operator()(node x,node y){return x.r>y.r;}};
17 // bool cmp(node x,node y) {return x.r>y.r;}
18 // bool cmp2(node x,node y) {return x.r<y.r;}
19 bool cmp3(node x,node y) {return x.l<y.l;}
20 priority_queue<node,vector<node>,cmp> q1;
21 priority_queue<node,vector<node>,cmp2> q2;
22 
23 char s[Maxn];
24 
25 bool vis[Maxn];
26 int op[Maxn][Maxn];
27 int main()
28 {
29     // int T;
30     // scanf("%d",&T);
31     // while(T--)
32     {
33         int n,m,k,l;
34         scanf("%d%d%d%d",&n,&m,&k,&l);
35         
36         int cnt=0,id;
37         for(int i=1;i<=n;i++)
38         {
39             scanf("%s",s+1);
40             for(int j=1;j<=m;j++)
41             {
42                 if((j==1||s[j-1]=='0')&&s[j]=='1') id=j;
43                 else if(j!=1&&s[j-1]=='1'&&s[j]=='0') t[++cnt].l=id,t[cnt].r=j-1,t[cnt].id=i;
44                 if(s[j]=='1'&&j==m) t[++cnt].l=id,t[cnt].r=m,t[cnt].id=i;
45             }
46         }
47         sort(t+1,t+1+cnt,cmp3);
48         // int qz=0;
49         while(!q1.empty()) q1.pop();
50         while(!q2.empty()) q2.pop();
51         int nw=0;
52         bool ok=1;
53         memset(vis,0,sizeof(vis));
54         for(int i=1;i<=m;i++)
55         {
56             int hh=0;
57             while(t[nw+1].l<=i&&nw<cnt) q1.push(t[++nw]);
58             while(!q2.empty()&&q2.top().r<i) {vis[q2.top().id]=0;q2.pop();}
59             while(q2.size()<k)
60             {
61                 if(q1.empty()||q1.top().r<i) {ok=0;break;}
62                 vis[q1.top().id]=1;
63                 q2.push(q1.top());q1.pop();
64                 hh++;
65                 if(hh>l&&i!=1) break;
66             }
67             if((hh>l&&i!=1)||!ok) {ok=0;break;}
68             while(hh<l&&!q1.empty()&&q1.top().r>q2.top().r)
69             {
70                 hh++;
71                 vis[q2.top().id]=0;
72                 q2.pop();
73                 vis[q1.top().id]=1;
74                 q2.push(q1.top());q1.pop();
75             }
76             op[i][0]=0;
77             for(int j=1;j<=n;j++) if(vis[j]) op[i][++op[i][0]]=j;
78         }
79         if(!ok) printf("1\n");
80         else
81         {
82             for(int i=1;i<=m;i++)
83             {
84                 for(int j=1;j<=op[i][0];j++) printf("%d ",op[i][j]);
85                 printf("\n");
86             }
87         }
88     }
89     return 0;
90 }
View Code

 

2017-04-24 20:03:42

posted @ 2017-04-24 20:03  konjak魔芋  阅读(216)  评论(0编辑  收藏  举报