• 2018年全国多校算法寒假训练营练习比赛(第四场)


    A: 石油采集

    刚开始题目读错了,乱交了4发,然后终于读对题目,想用匈牙利算法跑2分匹配,但是比赛的时候不会跑,赛后学了一下,补了一下

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 const int N = 55*55;
     4 string str[55];
     5 int cnt = 0, tot, n;
     6 int dx[4] = {1,-1,0,0};
     7 int dy[4] = {0,0,1,-1};
     8 int head[N], to[N], nt[N], link[N];
     9 bool vis[N];
    10 int id(int x, int y)
    11 {
    12     return x*n+y;
    13 }
    14 void add_edge(int u, int v)
    15 {
    16     to[tot] = v;
    17     nt[tot] = head[u];
    18     head[u] = tot++;
    19 }
    20 bool hun(int u)
    21 {
    22     for(int i = head[u]; ~i; i = nt[i]){
    23         if(!vis[to[i]]){
    24             vis[to[i]] = 1;
    25             if(-1 == link[to[i]]|| hun(link[to[i]])){
    26                 link[u] = to[i];
    27                 link[to[i]]=u;
    28                 return 1;
    29             }
    30         }
    31     }
    32     return 0;
    33 }
    34 int main()
    35 {
    36     ios::sync_with_stdio(false);
    37     cin.tie(0);
    38     cout.tie(0);
    39     int T, Case = 1;
    40     cin >> T;
    41     while(T--)
    42     {
    43         tot = 0, cnt = 0;
    44         memset(head, -1, sizeof(head));
    45         memset(link, -1, sizeof(link));
    46         cin >> n;
    47         for(int i = 0; i < n; i++)
    48             cin >> str[i];
    49         for(int i = 0; i < n; i++){
    50             for(int j = 0; j < n; j++){
    51                 if(str[i][j] == '#'){
    52                     for(int k = 0; k < 4; k++){
    53                         int tx = i + dx[k];
    54                         int ty = j + dy[k];
    55                         if(tx < 0 || tx >= n || ty < 0 || ty >= n) continue;
    56                         if(str[tx][ty] == '#') add_edge(id(i,j), id(tx,ty));
    57                     }
    58                 }
    59             }
    60         }
    61         for(int i = 0; i < n; i++){
    62             for(int j = 0; j < n; j++){
    63                 if(str[i][j] == '#'){
    64                     if(-1 == link[id(i,j)]){
    65                         memset(vis, 0, sizeof(vis));
    66                         if(hun(id(i,j)))
    67                             cnt++;
    68                     }
    69                 }
    70             }
    71         }
    72         cout <<"Case " << Case++ <<": " <<cnt << endl;
    73     }
    74     return 0;
    75 }
    View Code

    B: 道路建设

    一道很裸的最小生成数。

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 int pre[1000];
     4 struct Node
     5 {
     6     int u, v, c;
     7     bool operator < (const Node & x) const
     8     {
     9         return c < x.c;
    10     }
    11 }E[10000];
    12 int n, m, Max;
    13 int Find(int x)
    14 {
    15     if(x == pre[x]) return x;
    16     return pre[x] = Find(pre[x]);
    17 }
    18 int main()
    19 {
    20     ios::sync_with_stdio(false);
    21     cin.tie(0);
    22     cout.tie(0);
    23     while(cin >> Max >> n >> m )
    24     {
    25         for(int i = 1; i <= m; i++)
    26             pre[i] = i;
    27         for(int i = 1; i <= n; i++)
    28         {
    29             cin >> E[i].u >> E[i].v >> E[i].c;
    30         }
    31         sort(E+1, E+1+n);
    32         for(int i = 1; i <= n; i++)
    33         {
    34             int x = Find(E[i].u), y = Find(E[i].v);
    35             if(x == y)continue;
    36             Max -= E[i].c;
    37             if(Max < 0) break;
    38             pre[x] = y;
    39         }
    40         if(Max < 0)
    41             cout << "No
    ";
    42         else
    43         {
    44             int cnt = 0;
    45             for(int i = 1; i <= n; i++)
    46                 if(Find(i) == i) cnt++;
    47             if(cnt == 1) cout <<"Yes
    ";
    48             else cout <<"No
    ";
    49         }
    50     }
    51     return 0;
    52 }
    View Code

    C:求交集

    比赛的时候题目没仔细读,没注意到输入的时候2个集合就是升序的,然后偷懒用set瞎几把搞了一发,然后MLE了,最后还是写了瞎几把写了一个2分查找,勉强Ac了。

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 const int INF = 0x3f3f3f3f;
     4 int a[1000000+5];
     5 int ans[1000000+5];
     6 int n, m;
     7 bool check(int tmp)
     8 {
     9     int l = 1, r = n;
    10     while(l <= r)
    11     {
    12         int m = r+l >> 1;
    13         if(tmp == a[m]) return true;
    14         if(tmp < a[m]) r = m-1;
    15         else l = m+1;
    16     }
    17     return false;
    18 }
    19 int main()
    20 {
    21     while(~scanf("%d%d",&n,&m))
    22     {
    23         int tot = 0;
    24         int tmp;
    25         for(int i = 1; i <= n; i++)
    26         {
    27             scanf("%d",&a[i]);
    28         }
    29         sort(a+1, a+n+1);
    30         for(int i = 1; i <= m; i++)
    31         {
    32             scanf("%d",&tmp);
    33             if(check(tmp)) ans[tot++] = tmp;
    34         }
    35         if(tot==0) printf("empty
    ");
    36         else
    37         {
    38             sort(ans,ans+tot);
    39             for(int i = 0; i < tot; i++)
    40                 printf("%d%c",ans[i]," 
    "[tot==i+1]);
    41         }
    42     }
    43     return 0;
    44 }
    View Code

    D:小明的挖矿之旅

    也是赛后补的,直接看别人的规律补的,算出到达这个'.'点传送门数和出去这个'.'的传送门数(都是无法往外走的情况下),最后进来和出去的门数取大就好了。

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 string str[1005];
     4 int n, m;
     5 bool check1(int x, int y)
     6 {
     7     if(x > 0 && str[x-1][y] == '.')return true;
     8     if(y > 0 && str[x][y-1] == '.')return true;
     9     return false;
    10 }
    11 bool check2(int x, int y)
    12 {
    13     if(x+1 < n && str[x+1][y] == '.') return true;
    14     if(y+1 < m && str[x][y+1] == '.') return true;
    15     return false;
    16 }
    17 int main()
    18 {
    19     ios::sync_with_stdio(false);
    20     cin.tie(0);
    21     cout.tie(0);
    22     while(cin >> n >> m)
    23     {
    24         for(int i = 0; i < n; i++)
    25             cin >> str[i];
    26         int cnt = 0, tohere = 0, lefthere = 0;
    27         for(int  i = 0; i < n; i++)
    28         {
    29             for(int j = 0; j < m; j++)
    30             {
    31                 if(str[i][j] == '.')
    32                 {
    33                     cnt++;
    34                     if(!check1(i,j)) tohere++;
    35                     if(!check2(i,j)) lefthere++;
    36                 }
    37             }
    38         }
    39         if(cnt <= 1) cout << 0 << endl;
    40         else cout << max(tohere, lefthere) << endl;
    41     }
    42     return 0;
    43  
    44 }
    View Code

    E:通知小弟

    赛后补的, 比赛的时候也想到了强连通缩点, 但是和A一样,赛前也只是了解这个算法,没有具体实现过,赛后补的时候不小心写错了2个字符,修改了不下20发,才修改结束(自以为是的很了解了这个算法),然后早上队长说瞎几把乱贪心就可以过了(233,但是我还是想研究一下这个Tarjan算法)。
    将每个强连通图锁点, 然后找到入读为0的点,如果每个入读为0的点都能被Boss通知,那么所有人都能收到通知。

      1 #include<bits/stdc++.h>
      2 using namespace std;
      3 const int N =1100;
      4 int cnt = 0, tot, n, m, rtcnt, top;
      5 int head[N], to[N*250], nt[N*250];
      6 bool vis[N], ok[N];
      7 int a[N], rt[N], low[N];
      8 int dfn[N], in[N], ind[N], Stack[N];
      9 void init()
     10 {
     11     memset(vis, 0, sizeof(vis));
     12     memset(ind, 0, sizeof(ind));
     13     memset(ok, 0, sizeof(ok));
     14     memset(head, -1, sizeof(head));
     15     memset(low, 0, sizeof(low));
     16     memset(rt, 0, sizeof(rt));
     17     tot = 0;
     18     top = 0;
     19     cnt = 0;
     20     rtcnt = 0;
     21 }
     22 void add_edge(int u, int v)
     23 {
     24     to[tot] = v;
     25     nt[tot] = head[u];
     26     head[u] = tot++;
     27 }
     28 void dfs(int u)
     29 {
     30     low[u] = dfn[u] = ++cnt;
     31     vis[u] = in[u] = 1;
     32     Stack[++top] = u;
     33     for(int i = head[u]; ~i; i = nt[i])
     34     {
     35         int v = to[i];
     36         if(!vis[v])
     37         {
     38             dfs(v);
     39             low[u] = min(low[v], low[u]);
     40         }
     41         else if(in[v]) low[u] = min(low[v], low[u]);
     42     }
     43     if(low[u] == dfn[u])
     44     {
     45         rtcnt++;
     46         int v;
     47         while(top > 0)
     48         {
     49             v = Stack[top--];
     50             in[v] = 0;
     51             rt[v] = rtcnt;
     52             if(v == u) break;
     53         }
     54     }
     55 }
     56 void tarjan()
     57 {
     58     for(int i = 1; i <= n; i++)
     59         if(!vis[i]) dfs(i);
     60     for(int i = 1; i <= n; i++)
     61     {
     62         for(int j = head[i]; ~j; j=nt[j])
     63         {
     64             if(rt[i] != rt[to[j]])
     65                 ind[rt[to[j]]]++;
     66         }
     67     }
     68     int ret = 0;
     69     for(int i = 0; i < m; i++)
     70         ok[rt[a[i]]] = 1;
     71     for(int i = 1; i <= rtcnt; i++)
     72     {
     73         if(ind[i] == 0)
     74         {
     75             if(ok[i]) ret++;
     76             else
     77                 {
     78                     cout << -1 << endl;
     79                     return ;
     80                 }
     81         }
     82     }
     83     cout << ret << endl;
     84     return ;
     85 }
     86 int main()
     87 {
     88     ios::sync_with_stdio(false);
     89     cin.tie(0);
     90     cout.tie(0);
     91     while(cin >> n >> m)
     92     {
     93         init();
     94         for(int i = 0; i < m; i++)
     95             cin >> a[i];
     96         for(int i = 1; i <= n; i++)
     97         {
     98             int k, v;
     99             cin >> k;
    100             for(int j = 1; j <= k; j++)
    101             {
    102                 cin >> v;
    103                 add_edge(i,v);
    104             }
    105         }
    106         tarjan();
    107     }
    108     return 0;
    109 }
    View Code

    F:Call to your teacher

    注意有向图,然后搜索就好了,记得每次这个人被通知过了就标记一下,免得重复搜索。

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 const int N = 2005;
     4 bool vis[55];
     5 int head[55], cnt = 0,n,m;
     6 struct Node
     7 {
     8     int to;
     9     int nt;
    10 }E[N];
    11 void add(int u, int v)
    12 {
    13     E[cnt].to = v;
    14     E[cnt].nt = head[u];
    15     head[u] = cnt++;
    16 }
    17 void bfs()
    18 {
    19     queue<int> q;
    20     q.push(1);
    21     vis[1] = 1;
    22     while(!q.empty())
    23     {
    24         int tmp = q.front();
    25         q.pop();
    26         if(tmp == n) return ;
    27         for(int i = head[tmp]; ~i; i = E[i].nt)
    28         {
    29             int v = E[i].to;
    30             if(vis[v]) continue;
    31             vis[v] = 1;
    32             q.push(v);
    33         }
    34     }
    35 }
    36 int main()
    37 {
    38     ios::sync_with_stdio(false);
    39     cin.tie(0);
    40     cout.tie(0);
    41     while(cin >> n >> m )
    42     {
    43        cnt = 0;
    44        int u, v;
    45        memset(vis, 0, sizeof(vis));
    46        memset(head, -1, sizeof(head));
    47        for(int i = 1; i <= m; i++)
    48        {
    49            cin >> u >> v;
    50            add(u,v);
    51        }
    52        bfs();
    53        if(vis[n]) cout << "Yes
    ";
    54        else cout << "No
    ";
    55     }
    56     return 0;
    57 }
    View Code

     G:老子的意大利炮呢

    比赛的时候想着反向BFS,让李云龙去走路,写了半天MLE了。

    MLE代码

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 const int INF = 0x3f3f3f3f;
     4 const int N = 505;
     5 string str[105];
     6 int dx[4] = {1,-1,0,0};
     7 int dy[4] = {0,0,-1,1};
     8 int vis[2][2][2][105][105];
     9 int pos[5][2];
    10 int v1, v2, v3, ans, n, m;
    11 struct Node
    12 {
    13     int x, y, v;
    14     int f1, f2, f3;
    15     int t;
    16 }tmp, nt;
    17 void BFS()
    18 {
    19     tmp.x = pos[4][0], tmp.y = pos[4][1];
    20     tmp.f1 = tmp.f2 = tmp.f3 = 1;
    21     tmp.v = v1 + v2 + v3 + 1;
    22     tmp.t = 0;
    23     queue<Node> q;
    24     q.push(tmp);
    25     while(!q.empty())
    26     {
    27         tmp = q.front();
    28         q.pop();
    29         if(tmp.x == pos[0][0] && tmp.y == pos[0][1] && !tmp.f1 && !tmp.f2 && !tmp.f3)
    30         {
    31             ans = min(ans, tmp.t);
    32             continue;
    33         }
    34         if(ans < tmp.t) continue;
    35         nt.t = tmp.v + tmp.t;
    36         for(int i = 0; i < 4; i++)
    37         {
    38             nt.x = tmp.x + dx[i];
    39             nt.y = tmp.y + dy[i];
    40             nt.v = tmp.v;
    41             nt.f1 = tmp.f1, nt.f2 = tmp.f2, nt.f3 = tmp.f3;
    42             if(nt.x < 0 || nt.x >= n || nt.y < 0 || nt.y >= m ) continue;
    43             if(nt.x == pos[1][0] && nt.y == pos[1][1] && nt.f1) nt.f1 = 0, nt.v -= v1;
    44             if(nt.x == pos[2][0] && nt.y == pos[2][1] && nt.f2) nt.f2 = 0, nt.v -= v2;
    45             if(nt.x == pos[3][0] && nt.y == pos[3][1] && nt.f3) nt.f3 = 0, nt.v -= v3;
    46             if(nt.f1 && nt.f2 && nt.f3 && str[nt.x][nt.y] == '#') continue;
    47             if(vis[nt.f1][nt.f2][nt.f3][nt.x][nt.y] < nt.t) continue;
    48             vis[nt.f1][nt.f2][nt.f3][nt.x][nt.y] = nt.t;
    49             q.push(nt);
    50         }
    51     }
    52 }
    53 int main()
    54 {
    55     ios::sync_with_stdio(false);
    56     cin.tie(0);
    57     cout.tie(0);
    58     while(cin >> n >> m)
    59     {
    60         ans = 1e9;
    61         memset(vis, INF, sizeof(vis));
    62         for(int i = 0; i < n; i++)
    63             cin >> str[i];
    64         for(int i = 0; i < 5; i++)
    65         {
    66             cin >> pos[i][0] >> pos[i][1];
    67             pos[i][0]--; pos[i][1]--;
    68         }
    69         cin >> v1 >> v2 >> v3;
    70         BFS();
    71         cout << ans << endl;
    72     }
    73     return 0;
    74 }
    View Code

    后面烦恼的时候,突然想到更好的优化,墨迹了几分钟,修改了一下,就AC了,

    还是让李云龙去走,走到“最后一个零件”,然后让和尚从自己的位置最短的距离跑到另外2个零件在跑到这个零件,取最小耗时就好了。因为和尚可以带着零件翻墙,不包括意大利炮,所以走到其他2个位置的距离是定下来的。

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 const int INF = 0x3f3f3f3f;
     4 const int N = 505;
     5 string str[105];
     6 int dx[4] = {1,-1,0,0};
     7 int dy[4] = {0,0,-1,1};
     8 int vis[105][105];
     9 int pos[5][2];
    10 int v[5], ans, n, m;
    11 struct Node
    12 {
    13     int x, y;
    14     int t;
    15 }tmp, nt;
    16 int dis(int u, int v)
    17 {
    18     return abs(pos[u][0]-pos[v][0]) + abs(pos[u][1]-pos[v][1]);
    19 }
    20 void BFS()
    21 {
    22     tmp.x = pos[4][0], tmp.y = pos[4][1];
    23     tmp.t = 0;
    24     vis[tmp.x][tmp.y];
    25     queue<Node> q;
    26     q.push(tmp);
    27     while(!q.empty())
    28     {
    29         tmp = q.front();
    30         q.pop();
    31         for(int i = 1; i <= 3; i++)
    32         {
    33             if(tmp.x == pos[i][0] && tmp.y == pos[i][1])
    34             {
    35                 int tt = tmp.t * (v[1]+v[2]+v[3]+1);
    36                 int l = i-1;
    37                 int r = i+1;
    38                 if(l == 0) l = 3;
    39                 if(r == 4) r = 1;
    40                 int t1 = (v[l]+v[r]+1)*dis(l,i)+ (v[r]+1)*dis(l,r) + 1*dis(r,0);
    41                 int t2 = (v[l]+v[r]+1)*dis(r,i)+(v[l]+1)*dis(l,r)+1*dis(l,0);
    42                 tt = tt+ min(t1,t2);
    43                 ans = min(ans,tt);
    44             }
    45         }
    46         nt.t = tmp.t+1;
    47         for(int i = 0; i < 4; i++)
    48         {
    49             nt.x = tmp.x + dx[i];
    50             nt.y = tmp.y + dy[i];
    51             if(nt.x < 0 || nt.x >= n || nt.y < 0 || nt.y >= m) continue;
    52             if(str[nt.x][nt.y] == '#' || vis[nt.x][nt.y]) continue;
    53             vis[nt.x][nt.y] = 1;
    54             q.push(nt);
    55         }
    56     }
    57     return ;
    58 }
    59 int main()
    60 {
    61     ios::sync_with_stdio(false);
    62     cin.tie(0);
    63     cout.tie(0);
    64     while(cin >> n >> m)
    65     {
    66         ans = 1e9;
    67         memset(vis, 0, sizeof(vis));
    68         for(int i = 0; i < n; i++)
    69             cin >> str[i];
    70         for(int i = 0; i < 5; i++)
    71         {
    72             cin >> pos[i][0] >> pos[i][1];
    73             pos[i][0]--; pos[i][1]--;
    74         }
    75         cin >> v[1] >> v[2] >> v[3];
    76         BFS();
    77         cout << ans << endl;
    78     }
    79     return 0;
    80 }
    View Code

    H:老子的全排列呢

    全场最水的题,但是我不知道STL函数,最后手写的dfs搜索过的。

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 bool vis[10];
     4 int put[10];
     5 void P()
     6 {
     7     for(int i = 1; i <= 8; i++)
     8     {
     9         printf("%d%c",put[i]," 
    "[i == 8]);
    10     }
    11 }
    12 void dfs(int cnt)
    13 {
    14     if(cnt == 9)
    15     {
    16         P();
    17         return;
    18     }
    19     for(int i = 1; i <= 8; i++)
    20     {
    21         if(!vis[i])
    22         {
    23             vis[i] = 1;
    24             put[cnt] = i;
    25             dfs(cnt+1);
    26             vis[i] = 0;
    27         }
    28     }
    29 }
    30 int main()
    31 {
    32     ios::sync_with_stdio(false);
    33     cin.tie(0);
    34     cout.tie(0);
    35     memset(vis, 0, sizeof(vis));
    36     dfs(1);
    37     return 0;
    38 }
    View Code

    总结,比赛前的确了解AE2道题目的算法,但是没有自己去写过,还是要多联系联系,还有就是A题题目,没有仔细读,然后就乱交了4发,下次注意。总的来说还不错,比较是这4次比赛来的最好名次,但是很多小小的细节没有注意。

  • 相关阅读:
    【转载】分析商品日均销量(DMS)对促销商品选择的意义
    日志备份和差异备份还原中的常见问题示例(转自&邹建)
    SQL Server 2000中的完整备份、差异备份操作
    数据库差异备份与增量备份的不同之处
    差异备份和还原操作方法(转)
    SQL备份(全)
    Microsoft SQL2000 错误代码 (@@error)
    图解SQL的inner join(join)、left join、right join、full outer join、union、union all的区别
    arm-none-linux-gnueabi-gcc command not found
    关于ST-Link的internal command error问题的解决方法
  • 原文地址:https://www.cnblogs.com/MingSD/p/8445486.html
Copyright © 2020-2023  润新知