专栏首页数据结构与算法2017.5.20欢(bei)乐(ju)赛解题报告

2017.5.20欢(bei)乐(ju)赛解题报告

预计分数:100+20+50=first

实际分数:20+0+10=gg

水灾(sliker.cpp/c/pas) 1000MS  64MB

大雨应经下了几天雨,却还是没有停的样子。土豪CCY刚从外地赚完1e元回来,知道不久除了自己别墅,其他的地方都将会被洪水淹没。

CCY所在的城市可以用一个N*M(N,M<=50)的地图表示,地图上有五种符号:“. * X D S”。其中“X”表示石头,水和人都不能从上面经过。“.”表示平原,CCY和洪水都可以经过。“*”表示洪水开始地方(可能有多个地方开始发生洪水)。“D”表示CCY的别墅。“S”表示CCY现在的位置。

CCY每分钟可以向相邻位置移动,而洪水将会在CCY移动之后把相邻的没有的土地淹没(从已淹没的土地)。

求CCY回到别墅的最少时间。如果聪哥回不了家,就很可能会被淹死,那么他就要膜拜黄金大神涨RP来呼叫直升飞机,所以输出“ORZ hzwer!!!”。

输入文件 sliker.in

输出文件 sliker.out

Input

3 3

D.*

.S.

Output

3

Input

3 3

D.* …

..S

Output

ORZ hzwer!!!

Input

3 6

D…*.

.X.X..

….S.

Output

6

 做这道题的时候可以说思路来的还是非常快的,一眼就看出是BFS暴力,但是可能是太大意了吧,把洪水覆盖的vis数组误以为是人走过的

vis数组,so没了判重就gg了,不过我还是很好奇为什么样例都能过而且还能拿两个点。。。。后来拿到代码改了一下死活是90分,,其实

现在想想还是数据太弱了,如果出题人狠的话估计真的能把我卡到爆零无话可说。看了n遍之后发现一个细节就是没有考虑洪水把当前正在搜索的节点淹了的情况,但是怎么改呢?其实我在洪水扩展之前已经判断过一次了。然后把前面的复制了一遍发现不对,后来把pop删掉就对了。。也是比较mengbi

代码:

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<cmath>
  5 #include<queue>
  6 using namespace std;
  7 int n,m;
  8 int xx[7]={-1,+1,0,0};
  9 int yy[7]={0,0,-1,+1};
 10 struct peo
 11 {
 12     int juli;// 
 13     int x,y;
 14     int step;
 15 }now,nxt;
 16 int map[201][201];
 17 int bgx,bgy,homex,homey;
 18 int vis[201][201];// 被洪水淹没的地方,注意要map和vis同时判断 
 19 int ans=438438;
 20 int watercishu=1;
 21 int flag=0;
 22 int vis2[201][201];
 23 int calca(int xxx,int yyy)
 24 {
 25     return max(xxx,homex)-min(xxx,homex)+max(yyy,homey)-min(yyy,homey);
 26 }
 27 void init()
 28 {
 29     scanf("%d%d",&n,&m);
 30     for(int i=1;i<=n;i++)
 31         for(int j=1;j<=m;j++)
 32         {
 33             char p;
 34             cin>>p;
 35             if(p=='.')
 36             map[i][j]=0;// 都可以通过
 37             else if(p=='X')
 38             map[i][j]=1;// 都不可以通过
 39             else if(p=='S')
 40             {map[i][j]=2;//人现在的位置
 41             bgx=i;bgy=j;}
 42             else if(p=='*')
 43             map[i][j]=3,vis[i][j]=1;// 洪水开始的地方 
 44             else if(p=='D')
 45             {
 46                 map[i][j]=4;// 家
 47                 homex=i;
 48                 homey=j;    
 49             }
 50             
 51         }
 52 }
 53 void ex()
 54 {
 55     int flag=0;
 56     for(int i=1;i<=n;i++)
 57     {
 58         for(int j=1;j<=m;j++)
 59         {
 60             if(vis[i][j]==watercishu)
 61             {
 62                 for(int k=0;k<4;k++)
 63                 {
 64                     int wx=i+xx[k];
 65                     int wy=j+yy[k];
 66                     if(vis[wx][wy]==0&&map[wx][wy]!=1&&map[wx][wy]!=4&&wx>=1&&wx<=n&&wy>=1&&wy<=m)
 67                     {
 68                         vis[wx][wy]=vis[i][j]+1;
 69                     }
 70                 }
 71             }
 72         }
 73     }
 74     watercishu++;
 75 }
 76 void bfs()
 77 {
 78     queue<peo>q;
 79     now.x=bgx;now.y=bgy;now.step=0;now.juli=calca(bgx,bgy);
 80     q.push(now);
 81     int last=0;// 记录上一次洪水扩展时人走的步数 
 82     while(q.size()!=0)
 83     {
 84         peo p=q.front();
 85         if(vis[p.x][p.y]!=0)
 86         {
 87             q.pop();
 88             continue;
 89         }
 90         if(p.juli==0)
 91         {
 92             printf("%d",p.step);
 93             flag=1;
 94             return ;
 95         }
 96         
 97         q.pop();
 98         if(p.step>last)
 99         {
100             ex();// 洪水扩展
101             last=p.step; 
102         }
103         if(vis[p.x][p.y]!=0)
104         {
105             continue;
106         }
107         for(int i=0;i<4;i++)
108         {
109             int wx=p.x+xx[i];
110             int wy=p.y+yy[i];
111             if(vis2[wx][wy]==0&&vis[wx][wy]==0&&map[wx][wy]!=1&&wx>=1&&wx<=n&&wy>=1&&wy<=m)
112             {
113                 vis2[wx][wy]=1;
114                 nxt.x=wx;
115                 nxt.y=wy;
116                 nxt.step=p.step+1;
117                 nxt.juli=calca(wx,wy);
118                 q.push(nxt);
119             }
120         }
121         
122     }
123 }
124 int main()
125 {
126     freopen("sliker.in","r",stdin);
127     freopen("sliker.out","w",stdout);
128     init();
129     bfs();
130     if(flag==0)
131         printf("ORZ hzwer!!!");
132     return 0;
133 }

某种数列问题  (jx.cpp/c/pas) 1000MS 256MB

众所周知,chenzeyu97有无数的妹子(阿掉!>_<),而且他还有很多恶趣味的问题,继上次纠结于一排妹子的排法以后,今天他有非(chi)常(bao)认(cheng)真(zhe)去研究一个奇怪的问题。有一堆他的妹子站成一排,然后对于每个妹子有一个美丽度,当然美丽度越大越好,chenzeyu97妹子很多,但是质量上不容乐观,经常出现很多美丽度为负数的妹子(喜闻乐见),chenzeyu97希望从一排妹子里找出3队连续的妹子,使她们的美丽度和最大。注意,一个妹子不能被编入多个队伍而且一定要拿出三队,不然czy会闲着没事做~。

简单滴说就是:

给定一个数列,从中找到3个无交集的连续子数列使其和最大。

【输入文件】

第一行一个数n,表示数列长度。

接下来有n行,每行一个数,第i行为第i个数。

【输出文件】

仅有一个数,表示最大和。

【样例输入】 jx.in

10

-1

2

3

-4

0

1

-6

-1

1

-2

【样例输出】 jx.out

7

【样例说明】

第一队妹子取2,3。

第二队妹子取0,1。

第三队妹子取1。

【数据范围】

请大家放心,虽然chenzeyu97妹子无数,但是这次他叫来的个数n是有限的。=v=

对于30%的数据,妹子数不大于200。

对于60%的数据,妹子数不大于2000。

对于100%的数据,妹子数1000000。

而且,由于chenzeyu97没有CCR那样的影响力,所以他的妹子选完的最大美丽度和不超过maxlongint。(注:CCR随便选就爆long long,因为他是把妹狂魔=V=)。

考场上天真的以为只要把所有的正数序列找到然后排一遍序就可以了,但是现在想想好智障啊,而且问了问同学之后发现智障的还不止是我一个。=.=

错误思路:寻找所有正数序列并排序

代码:

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<cmath>
  5 #include<algorithm>
  6 #define LL long long 
  7 using namespace std;
  8 LL n;
  9 LL a[1000001];
 10 struct node
 11 {
 12     LL id;
 13     LL yanzhi;
 14     LL js;
 15 }xulie[1000001];
 16 LL num=0;
 17 LL vis[1000001];
 18 LL compxiaoyu(const LL a,const LL b)
 19 {
 20     return a>b;
 21 }
 22 LL compdayu(const node & a ,const node & b)
 23 {
 24     return a.yanzhi>b.yanzhi;
 25 }
 26 int main()
 27 {
 28     freopen("jx.in","r",stdin);
 29     freopen("jx.out","w",stdout);
 30     //ios::sync_with_stdio(false);
 31     cin>>n;
 32     for(LL i=1;i<=n;i++)
 33         cin>>a[i];
 34     for(LL i=1;i<=n;i++)
 35     {
 36         if(a[i]>=0&&vis[i]==0)
 37         {
 38             xulie[++num].id=i;
 39             xulie[num].js=0;
 40             for(LL j=i;a[j]>=0&&j<=n;j++)
 41             {
 42                 vis[j]=1;
 43                 xulie[num].yanzhi+=a[j];
 44                 xulie[num].js++;
 45             }
 46         }
 47     }
 48     /*for(LL i=1;i<=num;i++)
 49         cout<<xulie[i].yanzhi<<endl;*/
 50     if(num<3)
 51     {
 52         LL ans=0;
 53         LL zssl=0;
 54         for(LL i=1;i<=num;i++)
 55         {
 56             zssl+=xulie[i].js;
 57         }
 58         if(zssl>=3)
 59         {
 60             for(LL i=1;i<=num;i++)
 61             {
 62                 ans+=xulie[i].yanzhi;
 63             }
 64             //printf("%d",ans);
 65             cout<<ans;
 66         }
 67         else
 68         {
 69             sort(a+1,a+n+1,compxiaoyu);
 70             num=zssl;
 71             for(LL i=1;i<=n;i++)
 72             {
 73                 if(a[i]<0)
 74                 {
 75                     xulie[++num].yanzhi=a[i];
 76                     if(num==3)
 77                     break;
 78                 }
 79             }
 80             for(LL i=1;i<=3;i++)
 81             {
 82                 ans+=xulie[i].yanzhi;
 83             }
 84             //printf("%d",ans);
 85             cout<<ans;    
 86         }
 87         
 88     }
 89     else if(num==3)
 90     {
 91         LL ans=0;
 92         for(LL i=1;i<=3;i++)
 93         ans+=xulie[i].yanzhi;
 94         cout<<ans;
 95     }
 96     else if(num>3)
 97     {
 98         LL ans=0;
 99         sort(xulie+1,xulie+num+1,compdayu);
100         for(LL i=1;i<=3;i++)
101         {
102             ans+=xulie[i].yanzhi;
103         }
104         cout<<ans;
105     }
106     return 0;
107 }

正确思路:dp

用dp[i][j][0]表示前i个点,取了j段,第i个点没有取的最大值

用dp[i][j][1]表示前i个点,取了j段,第i个点取了的最大值

答案=max(dp[n][3][0],dp[n][3][1])

转移的时候考虑取第i个和不取i个两种情况

代码:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<cmath>
 5 using namespace std;
 6 int a[1000001];
 7 int dp[1000001][5][4];
 8 int main()
 9 {
10     int n;
11     scanf("%d",&n);
12     for(int i=1;i<=n;i++)
13         scanf("%d",&a[i]);
14     
15     for(int i=1;i<=n;i++)
16     {
17         for(int j=1;j<=3;j++)
18         {
19             dp[i][j][0]=max(dp[i-1][j][0],dp[i-1][j][1]);
20             dp[i][j][1]=max(dp[i][j][1],dp[i-1][j-1][0]+a[i]);
21             dp[i][j][1]=max(dp[i][j][1],dp[i-1][j][1]+a[i]);
22         }
23     }
24     printf("%d",max(dp[n][3][0],dp[n][3][1]));
25     return 0;
26 }

密码锁 1000MS 512MB

Input: password.in

Output: password.out

【题目描述】

hzwer有一把密码锁,由N个开关组成。一开始的时候,所有开关都是关上的。当且仅当开关x1,x2,x3,...xk为开,其他开关为关时,密码锁才会打开。

他可以进行M种的操作,每种操作有一个size[i],表示,假如他选择了第i种的操作的话,他可以任意选择连续的size[i]个格子,把它们全部取反。(注意,由于黄金大神非常的神,所以操作次数可以无限>_<)

本来这是一个无关紧要的问题,但是,黄金大神不小心他的钱丢进去了,没有的钱他哪里能逃过被chenzeyu97 NTR的命运?>_<  于是,他为了虐爆czy,也为了去泡更多的妹子,决定打开这把锁。但是他那么神的人根本不屑这种”水题”。于是,他找到了你。

你的任务很简单,求出最少需要多少步才能打开密码锁,或者如果无解的话,请输出-1。

【输入格式】

第1行,三个正整数N,K,M,如题目所述。

第2行,K个正整数,表示开关x1,x2,x3..xk必须为开,保证x两两不同。

第三行,M个正整数,表示size[i],size[]可能有重复元素。

【输出格式】

输出答案,无解输出-1。

【样例输入1】

10 8 2

1 2 3 5 6 7 8 9

3 5

【样例输出1】

2

【样例输入2】

3 2 1

1 2

3

【样例输出2】

-1

【数据规模】

对于50%的数据,1≤N≤20,1≤k≤5,1≤m≤3;

对于另外20%的数据,1≤N≤10000,1≤k≤5,1≤m≤30;

对于100%的数据,1≤N≤10000,1≤k≤10,1≤m≤100。

这道题。。一看就是一道非常高端大气上档次的题目。一开始我还想用KMP,但是发现这道题的重点并不是KMP。看了一眼数据范围发现50%的n是二十,,,二十??暴力!!!于是乎便开始搞BFS+map判重。跑了一下样例能过,自己造的极端数据也能过,-1的情况也考虑到了,心想怎么着也得搞个三四十吧,,但是很遗憾。。出题人也是比较言(lao)而(jian)有(ju)信(huan),前五个数据居然除了第一个点的n==4之外其他的n all == 20.。。。。。这么说来我写了130行的BFS和输出-1有什么区别????!!!!!

丢分原因:1.能力不够

     2.外界因素  

正确思路:

  对于区间取反 复杂度是O(n)
    但是因为这题序列只有01
    如果操作查分序列的话就快多了
    先搞出查分序列 然后bfs求出每两个点的1相互抵消最少操作次数
    因为最后的序列最多20个1 所以状丫dp搞一搞求出min操作次数
    
    
    注意到题目中的是区间修改,把沿途的位置取反,
    这个可以看做是在模2意义下,给区间的加一操作。在我们通常的思路中,对于区间的操作,原本是要修改区间长度个的位置的情况,我们都可以通过考虑它的差分序列,使得要修改的位置个数变成2个,我们要求最少的修改,使得原序列变成全0。

    所以对原序列进行差分,那么每次修改就是要你对i号位置和i+size[]模2意义下的加1。

    差分后的序列中,数值为1的个数是不会超过2k个,即不会超过20个。

    考虑每次对i和i+x改动的过程,如果原序列中,
    i号位置和i+x号位置都是0的话,我们这么改,没有任何必要。
    所以任意时刻,数值为1的位置个数是不会增加的,那么我们可以把每一个的1看成一个的石子,
    那么每次我们可以把石子往某个方向移动size[]步,如果移动之后的位置存在石子的话,就对对碰,消掉了。

    因为是对对碰,石子之间的关系肯定是一个匹配的关系,我们不妨求出Dist[i][j]表示,
    石子i要走到石子j的位置,至少需要移动多少步,那么我们可以枚举每一个石子,
    然后进行一遍的bfs即可,这一部分的复杂度是O(2kmn)。
    现在问题转化为有一个大小不超过20的完全图,我们想要求它的最小权最大匹配。

暴力代码

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<cmath>
  5 #include<map>
  6 #include<queue>
  7 using namespace std;
  8 int n,k,m;// 数字的个数 , 需要打开的个数,操作的个数 
  9 int ned[1001];// 需要打开的数字 
 10 int kong[1001];
 11 int what[1001];// 各种走法 
 12 int flag=0,ans=-1;
 13 map<string,int>mp;
 14 struct node
 15 {
 16     int nowing[1001];// 已经得到的答案
 17     int step;// 步数 
 18 }now,nxt;
 19 void makeans()
 20 {
 21     string ans;
 22     for(int i=1;i<=n;i++)
 23         ans=ans+(char)(ned[i]+48);
 24     mp[ans]=2;
 25     //cout<<ans<<endl;
 26 }
 27 int pd(node how)
 28 {
 29     string w;
 30     for(int i=1;i<=n;i++)
 31         w=w+(char)(how.nowing[i]+48);
 32     if(mp[w]==2)
 33     {
 34         ans=how.step;
 35         flag=1;
 36         return 1;
 37     }
 38     if(mp[w]==0)
 39     {
 40         mp[w]=1;
 41         return 1;
 42     }
 43 }
 44 
 45 void bfs()
 46 {
 47     for(int i=1;i<=n;i++)
 48         now.nowing[i]=kong[i];
 49     now.step=0;
 50     queue<node>q;
 51     q.push(now);
 52     while(q.size()!=0)
 53     {
 54         node p=q.front();
 55         q.pop();
 56         for(int i=1;i<=n;i++)// 对每一位进行操作 
 57         {
 58             for(int j=1;j<=m;j++)// 每一种操作 
 59             {
 60                 if(what[j]+i<=n)
 61                 {
 62                     memset(nxt.nowing,0,sizeof(nxt.nowing));
 63                     for(int k=1;k<=n;k++)
 64                         nxt.nowing[k]=p.nowing[k];
 65                     for(int k=i;k<=i+what[j]-1;k++)
 66                     {
 67                         if(nxt.nowing[k]==0)
 68                             nxt.nowing[k]=1;
 69                         else
 70                             nxt.nowing[k]=0;
 71                         nxt.step=p.step+1;
 72                         
 73                     }
 74                     if(pd(nxt)==1)// 没有出现过
 75                         {
 76                             if(flag==1)
 77                             {
 78                                 printf("%d",ans);
 79                                 break;
 80                             }
 81                             q.push(nxt);
 82                         }
 83                 }
 84                 if(flag==1)
 85                 break;
 86             }
 87             if(flag==1)
 88                 break;
 89         }
 90         if(flag==1)
 91                 break;
 92     }
 93 }
 94 int main()
 95 {
 96     freopen("password.in","r",stdin);
 97     freopen("password.out","w",stdout);
 98     scanf("%d%d%d",&n,&k,&m);
 99     for(int i=1;i<=k;i++)
100     {
101         int p;
102         scanf("%d",&p);
103         ned[p]=1;
104     }
105     for(int i=1;i<=m;i++)
106         scanf("%d",&what[i]);
107     makeans();
108     
109     bfs();
110     
111     if(flag==0)
112     {
113         printf("-1");
114     }
115     
116     return 0;
117 }

正确代码

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<queue>
 5 #define maxn 10010
 6 using namespace std;
 7 int n,m,k,size[110],a[maxn],c[maxn],s[maxn],cnt,step[110][110];
 8 int f[maxn],dis[maxn],dp[1<<22],inf;
 9 struct node
10 {
11     int x,t;
12 };
13 queue<node>q;
14 void Bfs(int S,int o)
15 {
16     while(!q.empty())q.pop();
17     memset(f,0,sizeof(f));
18     memset(dis,127/3,sizeof(dis));
19     inf=dis[0];
20     q.push((node)
21     {
22         S,0
23     });
24     f[S]=1;
25     dis[S]=0;
26     while(!q.empty())
27     {
28         node p=q.front();
29         q.pop();
30         for(int i=1; i<=k; i++)
31         {
32             int y=p.x+size[i];
33             if(y<=n&&f[y]==0)
34             {
35                 f[y]=1;
36                 dis[y]=p.t+1;
37                 q.push((node)
38                 {
39                     y,dis[y]
40                 });
41             }
42             y=p.x-size[i];
43             if(y>=1&&f[y]==0)
44             {
45                 f[y]=1;
46                 dis[y]=p.t+1;
47                 q.push((node)
48                 {
49                     y,dis[y]
50                 });
51             }
52         }
53     }
54     for(int i=1; i<=cnt; i++)
55         if(dis[c[i]]<inf)step[o][i]=dis[c[i]];
56         else step[o][i]=inf;
57 }
58 int main()
59 {
60 //    freopen("password.in","r",stdin);
61 //    freopen("password.out","w",stdout);
62     scanf("%d%d%d",&n,&m,&k);
63     for(int i=1; i<=m; i++)
64     {
65         int x;
66         scanf("%d",&x);
67         a[x]++;
68     }
69     for(int i=1; i<=k; i++)
70         scanf("%d",&size[i]);
71     n++;
72     for(int i=1; i<=n; i++)
73         s[i]=a[i]-a[i-1];
74     for(int i=1; i<=n; i++)
75         if(s[i])
76             c[++cnt]=i;
77     for(int i=1; i<=cnt; i++)
78         Bfs(c[i],i);
79     memset(dp,127/3,sizeof(dp));
80     inf=dp[0];
81     dp[0]=0;
82     for(int i=0; i<=(1<<cnt)-1; i++)
83     {
84         int j;
85         for(int k=1; k<=cnt; k++)
86             if((1<<k-1)&i)
87             {
88                 j=k;
89                 break;
90             }
91         for(int k=1; k<=cnt; k++)
92             if((1<<k-1)&i)
93                 dp[i]=min(dp[i],dp[i^(1<<j-1)^(1<<k-1)]+step[j][k]);
94     }
95     if(dp[(1<<cnt)-1]==inf)printf("-1\n");
96     else printf("%d\n",dp[(1<<cnt)-1]);
97     return 0;
98 }
  1 /*
  2     将每个点拆成俩个点x,x’,能匹配的点xy从x向y’
  3     连边权值为1费用    Dist[i][j],源点向x连边,x’向汇连边,都是权值1    费用0,然后一遍    最小费用最大流就可以出解
  4 */
  5 #include <cstring>
  6 #include <cstdio>
  7 #include <queue>
  8 
  9 #define Max 10005
 10 #define INF 1e8
 11 
 12 namespace Z 
 13 {
 14     void read (int &now)
 15     {
 16         now = 0;
 17         register char word = getchar ();
 18         while (word < '0' || word > '9')
 19             word = getchar ();
 20         while (word >= '0' && word <= '9')
 21         {
 22             now = now * 10 + word - '0';
 23             word = getchar ();
 24         }
 25     }
 26     
 27     inline int min (const int &_Qos_swc, const int &_Cos_ses)
 28     {
 29         return _Qos_swc < _Cos_ses ? _Qos_swc : _Cos_ses;
 30     }
 31 }
 32 
 33 int S, T = 45;
 34 int M, N, K;
 35 int key[Max];
 36 int size[Max];
 37 int Answer;
 38 int Count;
 39 
 40 int date[Max];
 41 int number[Max];
 42 
 43 int cost[Max / 100][Max / 100];
 44 
 45 bool visit[Max];
 46 int dis[Max];
 47 
 48 void Bfs (int res)
 49 {
 50     memset (visit, false, sizeof (visit));
 51     std :: queue <int> Queue;
 52     visit[res] = true;
 53     dis[res] = 0;
 54     Queue.push (res);
 55     int now;
 56     while (!Queue.empty ())
 57     {
 58         now = Queue.front ();
 59         Queue.pop ();
 60         for (int i = 1; i <= M; i++)
 61         {
 62             if (now + size[i] <= N && (!visit[size[i] + now]))
 63             {
 64                 visit[size[i] + now] = true;
 65                 dis[now + size[i]] = dis[now] + 1;
 66                 Queue.push (now + size[i]);
 67             }
 68             if (now - size[i] > 0 && (!visit[now - size[i]]))
 69             {
 70                 visit[now - size[i]] = true;
 71                 dis[now - size[i]] = dis[now] + 1;
 72                 Queue.push (now - size[i]);
 73             }
 74         }
 75     }
 76 }
 77 
 78 class Net_Flow_Type
 79 {
 80     private : 
 81     
 82         struct Edge_Date
 83         {
 84             int from;
 85             int to;
 86             int flow;
 87             int next;
 88             int cost;
 89         }
 90         edge[Max << 2];
 91         
 92         int Edge_Count;
 93         int edge_list[Max];
 94         int deep[Max];
 95         int pre[Max];
 96         
 97     public :
 98         
 99         void Prepare ()
100         {
101             Edge_Count = 1;
102         }
103         
104         inline void AddEdge (int from, int to, int flow, int cost)
105         {
106             Edge_Count++;
107             edge[Edge_Count].from = from;
108             edge[Edge_Count].to = to;
109             edge[Edge_Count].flow = flow;
110             edge[Edge_Count].cost = cost;
111             edge[Edge_Count].next = edge_list[from];
112             edge_list[from] = Edge_Count;
113             Edge_Count++;
114             edge[Edge_Count].from = to;
115             edge[Edge_Count].to = from;
116             edge[Edge_Count].flow = 0;
117             edge[Edge_Count].cost = -cost;
118             edge[Edge_Count].next = edge_list[to];
119             edge_list[to] = Edge_Count;
120         }
121         
122         bool Spfa ()
123         {
124             for (int i = 0; i <= T; i++)
125                 deep[i] = INF;
126             std :: queue <int> Queue;
127             memset (visit, false, sizeof visit);
128             Queue.push (S);
129             deep[S] = 0;
130             visit[S] = true;
131             int now;
132             while (!Queue.empty ())
133             {
134                 now = Queue.front ();
135                 Queue.pop ();
136                 for (int i = edge_list[now]; i; i = edge[i].next)
137                     if (edge[i].flow && deep[now] + edge[i].cost < deep[edge[i].to])
138                     {
139                         deep[edge[i].to] = deep[now] + edge[i].cost;
140                         pre[edge[i].to] = i;
141                         if (!visit[edge[i].to])
142                         {
143                             visit[edge[i].to] = true;
144                             Queue.push (edge[i].to);
145                         }
146                     }
147                 visit[now] = false;
148             }
149             return deep[T] < INF;
150         }
151         
152         void Dinic ()
153         {
154             while (Spfa ())
155             {
156                 int res = INF;
157                 for (int i = pre[T]; i; i = pre[edge[i].from])
158                     res = Z :: min (res, edge[i].flow);
159                 for (int i = pre[T]; i; i = pre[edge[i].from])
160                 {
161                     edge[i].flow -= res;
162                     edge[i ^ 1].flow += res;
163                     Answer += edge[i].cost * res;
164                 }
165             }
166         }
167         
168         void Insert_Edges ()
169         {
170             int o = 0;
171             for (int i = 1; i <= Count; i++)
172             {
173                 AddEdge (S, i, 1, 0);
174                 AddEdge (i + Count, T, 1, 0); 
175             }
176             for (int i = 1; i <= Count; i++)
177                 for (int j = 1; j <= Count; j++)
178                     if (i != j && cost[i][j] != INF)
179                         AddEdge (i, j + Count, 1, cost[i][j]);
180 //            for (int i = 1; i <= Edge_Count; i++)
181 //                printf ("%d %d %d %d %d \n", edge[i].from, edge[i].to, edge[i].flow, edge[i].cost, edge[i].next);
182         }
183     
184 };
185 
186 
187 Net_Flow_Type Make;
188 
189 int main (int argc, char *argv[])
190 {
191     freopen ("password.in", "r", stdin);
192     freopen ("password.out", "w", stdout);
193     Z :: read (N);
194     Z :: read (K);
195     Z :: read (M);
196     N++;
197     Make.Prepare (); 
198     for (int i = 1; i <= K; i++)
199     {
200         Z :: read (key[i]);
201         date[key[i]] = 1;
202     }
203     for (int i = 1; i <= M; i++)
204         Z :: read (size[i]);
205     for (int i = N; i; i--)
206         date[i] ^= date[i - 1];
207     for (int i = 1; i <= N; i++)
208         if (date[i])
209             number[i] = ++Count;
210     for (int i = 1; i <= N; i++)
211         if (date[i])
212         {
213             Bfs (i); 
214             for (int j = 1; j <= N; j++)
215             {
216                 if (!number[j])
217                     continue;
218                 if (!visit[j])
219                     cost[number[i]][number[j]] = INF;
220                 else
221                     cost[number[i]][number[j]] = dis[j];
222             }
223         }
224     Make.Insert_Edges (); 
225     Make.Dinic ();
226     printf ("%d", (Answer >> 1)); 
227     return 0;
228 }

总结:

这次考试如果没有T1的话考的还算是非常好的。

主要是这次考试之后我发现了很多事情

一.自己的优点:

1.思路来的比较快,但是有些思路是错的,经不起推敲,但是有时候错的思路能为正确的思路奠定基础

(T1是这样,不啰嗦了)

2.coding代码的能力比较强,特别是在调试方面,T1大部分同学都用了一个半小时到三小时不等,但是我用了不到一个小时(虽然有点小错误)。三道题加起来代码写了接近380行。。也算是奇迹

二.自己的缺点

细节!细节!细节!,细节决定成败,这句话在oi的赛场上体现的淋漓尽致。以后在做题的时候感觉可以找一下在乒乓球赛场上的感觉(我在乒乓球赛场上稳如泰山,全县rank1就是靠这个拿的)。相信我的oi赛场和乒乓球赛场肯定有很多可以互补的地方

三.考试经验

1.在做搜索题目的时候,必须要自己手动生产一下比较简单但是数据规模比较大的数据。(毕竟每道题都有几个这样的测试点)

2.最后一题其实我可以拿到20分的,怎么搞呢?只要在搜索里面加个计数,当这个数非常大的时候退出就可以了

That all

加油!

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • BZOJ3143: [Hnoi2013]游走(期望DP 高斯消元)

    Description 一个无向连通图,顶点从1编号到N,边从1编号到M。  小Z在该图上进行随机游走,初始时小Z在1号顶点,每一步小Z以相等的概率随机选 择当...

    attack
  • 树上莫队算法

    attack
  • 04:垂直直方图

    4:垂直直方图 总时间限制: 1000ms 内存限制: 65536kB描述 输入4行全部由大写字母组成的文本,输出一个垂直直方图,给出每个字符出现的次数。注...

    attack
  • OpenCV图像处理专栏十 | 利用中值滤波进行去雾

    这是OpenCV图像处理专栏的第十篇文章,介绍一种利用中值滤波来实现去雾的算法。这个方法发表于国内的一篇论文,链接我放附录了。

    BBuf
  • LeetCode 323. 无向图中连通分量的数目(并查集)

    给定编号从 0 到 n-1 的 n 个节点和一个无向边列表(每条边都是一对节点),请编写一个函数来计算无向图中连通分量的数目。

    Michael阿明
  • BZOJ3143: [Hnoi2013]游走(期望DP 高斯消元)

    Description 一个无向连通图,顶点从1编号到N,边从1编号到M。  小Z在该图上进行随机游走,初始时小Z在1号顶点,每一步小Z以相等的概率随机选 择当...

    attack
  • 挑战程序竞赛系列(23):3.2折半枚举

    版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.n...

    用户1147447
  • 树上莫队算法

    attack
  • BZOJ2535: [Noi2010]Plane 航空管制2(拓扑排序 贪心)

    首先不难想到拓扑排序,但是直接对原图按\(k\)从小到大拓扑排序是错的。因为当前的\(k\)大并不意味着后面的点\(k\)也大

    attack
  • 浙大版《C语言程序设计(第3版)》题目集 习题4-6 水仙花数

    水仙花数是指一个N位正整数(N≥3),它的每个位上的数字的N次幂之和等于它本身。例如:153=13+53+33。 本题要求编写程序,计算所有N位水仙花数。

    C you again 的博客

扫码关注云+社区

领取腾讯云代金券