Codeforces Round #290 (Div. 2)【DFS、拓扑排序、DP、最大流】

题目链接


A. Fox And Snake

  蛇形填数,C语言基础问题。

#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <unordered_map>
#include <unordered_set>
#define _ABS(x, y) ( x > y ? (x - y) : (y - x) )
#define lowbit(x) ( x&( -x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f
#define efs 1e-7
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
#define MP(a, b) make_pair(a, b)
using namespace std;
typedef unsigned long long ull;
typedef unsigned int uit;
typedef long long ll;
int N, M;
char mp[55][55];
int main()
{
    scanf("%d%d", &N, &M);
    for(int i=0; i<N; i+=2)
    {
        for(int j=0; j<M; j++) mp[i][j] = '#';
    }
    for(int i=1; i<N; i+=4)
    {
        for(int j=0; j<M-1; j++) mp[i][j] = '.';
        mp[i][M - 1] = '#';
    }
    for(int i=3; i<N; i+=4)
    {
        for(int j=1; j<M; j++) mp[i][j] = '.';
        mp[i][0] = '#';
    }
    for(int i=0; i<N; i++) printf("%s\n", mp[i]);
    return 0;
}

 


B. Fox And Two Dots

  DFS

  这题稍微卡了一会,是因为一开始想既然要构成环的话,那么是否可以用并查集来维护,如果判断到相等的时候就是直接Yes了?但是显然存在一个问题,就是你不知道你是怎样走的,于是我想了下,我似乎可以用dfs来跑深度,这样,如果跑到一个深度和毗邻的点的深度差大于等于3的时候并且还是同一种颜色的,就一定是构成了size大于等于4的环了。

#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <unordered_map>
#include <unordered_set>
#define _ABS(x, y) ( x > y ? (x - y) : (y - x) )
#define lowbit(x) ( x&( -x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f
#define efs 1e-7
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
#define MP(a, b) make_pair(a, b)
using namespace std;
typedef unsigned long long ull;
typedef unsigned int uit;
typedef long long ll;
const int maxN = 55;
const int dir[4][2] =
{
    -1, 0,
    0, -1,
    0, 1,
    1, 0
};
int N, M, _UP, root[maxN * maxN];
inline int _id(int x, int y) { return (x - 1) * M + y; }
char mp[maxN][maxN];
int fid(int x) { return x == root[x] ? x : root[x] = fid(root[x]); }
pair<int, int> it;
vector<pair<int, int>> vt[27];
inline bool In_map(int x, int y) { return x >= 1 && y >= 1 && x <= N && y <= M; }
struct node
{
    int x, y, step;
    node(int a=0, int b=0, int c=0):x(a), y(b), step(c) {}
};
queue<node> Q;
int vis[maxN][maxN] = {0};
bool check_OK(int sx, int sy, int xx, int yy)
{
    if(sx == xx && abs(sy - yy) == 1)
    {
        if(mp[sx][sy] == mp[xx][yy] && abs(vis[sx][sy] - vis[xx][yy]) >= 3) return true;
    }
    else if(sy == yy && abs(xx - sx) == 1)
    {
        if(mp[sx][sy] == mp[xx][yy] && abs(vis[sx][sy] - vis[xx][yy]) >= 3) return true;
    }
    return false;
}
bool OK = false;
int SX, SY;
void dfs(int sx, int sy, int deep)
{
    for(int i=0, xx, yy; i<4; i++)
    {
        xx = sx + dir[i][0]; yy = sy + dir[i][1];
        if(!In_map(xx, yy)) continue;
        if(mp[sx][sy] ^ mp[xx][yy]) continue;
        if(vis[xx][yy])
        {
            if(check_OK(sx, sy, xx, yy))
            {
                OK = true;
                return;
            }
            continue;
        }
        vis[xx][yy] = deep + 1;
        dfs(xx, yy, deep + 1);
        if(OK) return;
    }
}
int main()
{
    scanf("%d%d", &N, &M);
    _UP = N * M;
    for(int i=1; i<=_UP; i++) root[i] = i;
    for(int i=1, col; i<=N; i++)
    {
        scanf("%s", mp[i] + 1);
        for(int j=1; j<=M; j++)
        {
            col = mp[i][j] - 'A';
            vt[col].push_back(MP(i, j));
        }
    }
    for(int i=0, len; i<26; i++)
    {
        len = (int)vt[i].size();
        for(int j=0; j<len; j++)
        {
            it = vt[i][j];
            if(vis[it.first][it.second]) continue;
            SX = it.first; SY = it.second;
            vis[SX][SY] = 1;
            dfs(it.first, it.second, 1);
            if(OK) { printf("Yes\n"); return 0; }
        }
    }
    printf("No\n");
    return 0;
}

  这题代码写的不是很好,因为训练赛的时候一开始想了跑Tarjan还有各种玄学东西来弄,但是都没有考虑到无向的这一层面,如果建无向图Tarjan又不好确定size,所以最后想到了dfs这个玄学的存在。


C. Fox And Names

  拓扑排序

  题意的这层描叙,简直就是差把“这就是到拓扑,建边跑吧”给说出来了。很显然,由于这里的N很小,字符串的长度也是很小,我们在字符串比较上甚至不需要过多的优化操作,我们可以利用O(N^{2} * len)如此的暴力解法来解决问题。然后建了边之后直接拓扑即可。

#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <unordered_map>
#include <unordered_set>
#define _ABS(x, y) ( x > y ? (x - y) : (y - x) )
#define lowbit(x) ( x&( -x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f
#define efs 1e-7
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
#define MP(a, b) make_pair(a, b)
using namespace std;
typedef unsigned long long ull;
typedef unsigned int uit;
typedef long long ll;
const int maxN = 105;
int N, len[maxN];
char s[maxN][maxN];
int head[30], cnt, du[30] = {0};
struct Eddge
{
    int nex, to;
    Eddge(int a=-1, int b=0):nex(a), to(b) {}
}edge[maxN * maxN];
inline void addEddge(int u, int v)
{
    edge[cnt] = Eddge(head[u], v);
    head[u] = cnt++;
}
int _Index[maxN] = {0}, tot;
char ans[30];
queue<int> Q;
void tp_sort()
{
    for(int i=0; i<26; i++)
    {
        if(!du[i]) Q.push(i);
    }
    int u;
    while(!Q.empty())
    {
        u = Q.front(); Q.pop();
        _Index[u] = ++tot;
        for(int i=head[u], v; ~i; i=edge[i].nex)
        {
            v = edge[i].to;
            du[v]--;
            if(du[v] == 0) Q.push(v);
        }
    }
}
inline void init()
{
    cnt = 0;
    for(int i=0; i<26; i++) head[i] = -1;
}
int main()
{
    scanf("%d", &N);
    init();
    for(int i=1; i<=N; i++) scanf("%s", s[i] + 1);
    for(int i=1; i<=N; i++) len[i] = (int)strlen(s[i] + 1);
    bool flag = true;
    for(int i=1, u, v, min_len; i<=N; i++)
    {
        for(int j=i + 1; j<=N; j++)
        {
            min_len = min(len[i], len[j]);
            for(int k=1; k<=min_len; k++)
            {
                if(s[i][k] == s[j][k])  //相等的情况
                {
                    if(k == min_len && len[i] > len[j]) flag = false;   //如果是到了最后一位了
                    continue;
                }
                u = s[i][k] - 'a'; v = s[j][k] - 'a';
                addEddge(u, v);
                du[v]++;
                break;
            }
        }
    }
    if(!flag) { printf("Impossible\n"); return 0; }
    tp_sort();
    for(int i=0; i<26; i++)
    {
        if(!_Index[i]) { flag = false; break; }
    }
    if(!flag) { printf("Impossible\n"); return 0; }
    for(int i=0; i<26; i++) ans[_Index[i]] = 'a' + i;
    for(int i=1; i<=26; i++) printf("%c", ans[i]);
    printf("\n");
    return 0;
}

 


D. Fox And Jumping

  DP

  还是挺好的一道DP,主要是我们在【x - L, x + L】这里的想法,首先我们想由几种Li来构成任意的1,这里可以想到,我们可以用gcd来维护。也就是,我们需要取一部分的Li使得最后的合成gcd为1,并且呢,花费还是最小的。

  那么,可以用一个背包DP来做,我们有N个数它们都有对应的价值,所以的话,我们可以一一放入,并且更新gcd,但是为了维护起来方便一点,我定义了当目前为0的时候,需要的花费为0,因为gcd(x, 0) = 0这是我们gcd()的写法。

  再者,这里是不能用unordered_map的,因为它是对于第一维直接哈希Hash了,众所周知,我们是不能对一个Hash过了的值进行一些其他的操作了的。

#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <unordered_map>
#include <unordered_set>
#define _ABS(x, y) ( x > y ? (x - y) : (y - x) )
#define lowbit(x) ( x&( -x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f
#define efs 1e-7
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
#define MP(a, b) make_pair(a, b)
using namespace std;
typedef unsigned long long ull;
typedef unsigned int uit;
typedef long long ll;
const int maxN = 305;
int N, c[maxN], L[maxN];
int gcd(int a, int b) { return b == 0 ? a : gcd(b, a % b); }
map<int, int> dp;
map<int, int>::iterator it;
int main()
{
    scanf("%d", &N);
    for(int i=1; i<=N; i++) scanf("%d", &L[i]);
    for(int i=1; i<=N; i++) scanf("%d", &c[i]);
    dp[0] = 0;
    for(int i=1, val, cost, nex_val, nex_c; i<=N; i++)
    {
        for(it = dp.begin(); it != dp.end(); it++)
        {
            val = it->first; cost = it->second;
            nex_val = gcd(val, L[i]);
            nex_c = cost + c[i];
            if(!dp.count(nex_val)) dp[nex_val] = nex_c;
            else if(dp[nex_val] > nex_c) dp[nex_val] = nex_c;
        }
    }
    if(!dp.count(1)) printf("-1\n");
    else printf("%d\n", dp[1]);
    return 0;
}

 


E. Fox And Dinner

  利用网络流最大流解决(大于等于)三元环的环的构造问题。

  首先,如果去跑KM等等的二分图上的直接的操作自然是不对的,因为一个点必须要匹配两个点,这就是大于等于三元环的环的解决方式,所以一直很懵,该怎样解决这个问题呢?

  然后的话,想的办法就是网络流的最大流了,我们知道,如果一个点在三元环内的话,那么它出去的点是唯一的,进来的点也是唯一的,但是它的度是二。我们反思一下KM的最大(单位)权匹配(匈牙利算法),是可以解决环构造的(解决单位环(可以直接从二元开始)、二元环、三元环……),但是我们现在是必须要从三元环起步。

  根据性质,我们现在要做一些改变了。

  现在,我们找一下规律,如果它是奇数,那么跟它匹配的点一定就是偶数了,如果它是偶数,那么能与它匹配的点一定也就是奇数了,所以,有了这一条性质之后,我们现在可以把图拆成一个二分图了,左边是奇数值的点,右边是偶数值的点,然后再看,我们打个预处理的质数筛,我们就可以把对应的关系给列出来了,流为单位一。

  然后呢,因为每个点的出度都是2,所以呢,从源点到奇数点的流为2,偶数点到汇点的流为2,就可以保证我们所构成的环一定是个大于等于三元环的。

#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <unordered_map>
#include <unordered_set>
#define _ABS(x, y) ( x > y ? (x - y) : (y - x) )
#define lowbit(x) ( x&( -x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f
#define efs 1e-7
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
#define MP(a, b) make_pair(a, b)
using namespace std;
typedef unsigned long long ull;
typedef unsigned int uit;
typedef long long ll;
const int maxN = 205, S = 0;
int N, a[maxN], flow[maxN][maxN] = {0}, T;
struct Prim_num
{
    bool Prim[20005];
    Prim_num()
    {
        memset(Prim, true, sizeof(Prim));
        for(int i=2; i<=20000; i++)
        {
            if(Prim[i])
            {
                for(int j=2 * i; j<=20000; j+=i)
                {
                    Prim[j] = false;
                }
            }
        }
    }
    inline void solve()
    {
        
    }
}PP;
int deep[maxN] = {0};
inline bool bfs()
{
    queue<int> Q;
    for(int i=0; i<=T; i++) deep[i] = 0;
    deep[S] = 1; Q.push(S);
    while(!Q.empty())
    {
        int u = Q.front(); Q.pop();
        for(int i=0; i<=T; i++)
        {
            if(flow[u][i] && !deep[i])
            {
                deep[i] = deep[u] + 1;
                Q.push(i);
            }
        }
    }
    return deep[T];
}
int dfs(int u, int dist)
{
    if(u == T) return dist;
    for(int i=0, di; i<=T; i++)
    {
        if(deep[u] + 1 == deep[i] && flow[u][i])
        {
            di = dfs(i, min(dist, flow[u][i]));
            if(di)
            {
                flow[u][i] -= di; flow[i][u] += di;
                return di;
            }
        }
    }
    return 0;
}
int Dinic()
{
    int ans = 0, tmp;
    while(bfs())
    {
        while((tmp = dfs(S, N))) ans += tmp;
    }
    return ans;
}
vector<int> nex[maxN];
bool vis[maxN] = {false};
vector<int> vt;
vector<vector<int>> ans;
inline void solve()
{
    for(int i=1; i<=N; i++)
    {
        if((a[i] & 1) == 0) continue;
        for(int j=1; j<=N; j++)
        {
            if(a[j] & 1) continue;
            if(!PP.Prim[a[i] + a[j]]) continue;
            if(!flow[i][j])
            {
                nex[i].push_back(j);
                nex[j].push_back(i);
            }
        }
    }
    for(int i=1; i<=N; i++)
    {
        if(vis[i]) continue;
        vis[i] = true;
        vt.clear();
        vt.push_back(i);
        int now = nex[i][0];
        while(!vis[now])
        {
            vt.push_back(now);
            vis[now] = true;
            if(vis[nex[now][0]]) now = nex[now][1];
            else now = nex[now][0];
        }
        ans.push_back(vt);
    }
    int len = (int)ans.size();
    printf("%d\n", len);
    for(int i=0, siz; i<len; i++)
    {
        siz = (int)ans[i].size();
        printf("%d", siz);
        for(int j=0; j<siz; j++) printf(" %d", ans[i][j]);
        printf("\n");
    }
}
int main()
{
    scanf("%d", &N);
    T = N + 1;
    for(int i=1; i<=N; i++)
    {
        scanf("%d", &a[i]);
        if(a[i] & 1) flow[S][i] = 2;
        else flow[i][T] = 2;
    }
    for(int i=1; i<=N; i++)
    {
        if((a[i] & 1) == 0) continue;
        for(int j=1; j<=N; j++)
        {
            if(a[j] & 1) continue;
            if(!PP.Prim[a[i] + a[j]]) continue;
            flow[i][j] = 1;
        }
    }
    int Max_Flow = Dinic();
    if(Max_Flow ^ N) { printf("Impossible\n"); return 0; }
    solve();
    return 0;
}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Wuliwuliii

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值