2020 HDU Multi-University Training Contest 4

2020 HDU Multi-University Training Contest 4

1002 Blow up the Enemy

链接:HDU6803 Blow up the Enemy

代码

(队友的代码)

#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
int data[1002];
int main(void){
    int t;
    cin >> t;
    int n;
    while(t--){
        scanf("%d", &n);
        int ai,di;
        int minn=999999999;
        for(int i=1;i<=n;i++){
            scanf("%d %d", &ai, &di);
            if((100%ai)==0){
                data[i]= di*(100/ai-1);
            }else{
                data[i] = di*(100/ai);
            }
            if(minn > data[i]){
                minn = data[i];
            }
        }
        int ans = 0;
        for(int i=1;i<=n;i++){
            if(minn < data[i]){
                ans += 10;
            }else if(minn == data[i]){
                ans += 5;
            }else{
                ans += 0;
            }
        }
        double res = (double)ans/(double)n/10.0;
        cout << res << endl;
    }
    return 0;
}
1005 Equal Sentences

链接:HDU6808 Equal Sentences

题意
思路
  • 简单 D P DP DP
代码
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int MAXN = 1e5 + 7;
// const int INF = ;
const int MOD = 1e9 + 7;
// const int DIRX[] = {};
// const int DIRY[] = {};

int T;
int n;
string str;
string tmp, word;
int cnt;
int dp[MAXN][2];
int vis[MAXN];
int ans;

int32_t main(void)
{
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cin >> T;
    while (T--)
    {
        memset(vis, 0, sizeof(vis));
        cnt = 0;
        ans = 0;
        word = "";
        cin >> n;
        for (int i = 1; i <= n; ++i)
        {
            cin >> str;
            if (str != word)
            {
                cnt++;
                word = str;
            }
            vis[i] = cnt;
        }
        // cout << cnt << endl;
        dp[0][0] = dp[0][1] = 0;
        dp[1][0] = 1;
        dp[1][1] = 0;
        for (int i = 2; i <= n; ++i)
        {
            if (vis[i] != vis[i - 1])
            {
                dp[i][0] = dp[i - 1][0] + dp[i - 1][1] % MOD;
                dp[i][1] = dp[i - 1][0] % MOD;
            }
            else
            {
                dp[i][0] = dp[i - 1][0] + dp[i - 1][1] % MOD;
                dp[i][1] = 0 % MOD;
            }
        }
        ans = dp[n][0] + dp[n][1];
        ans %= MOD;
        cout << ans << endl;
    }
    return 0;
}
1011 Kindergarten Physics

链接:HDU6812 Kindergarten Physics

???

1004 Deliver the Cake

链接:HDU6805 Deliver the Cake

题意
  • n n n 个点, m m m 条边的无向图每条边边权 d d d
  • 每个点有 L ,   M ,   R L, \ M, \ R L, M, R 三种状态
    • M M M 状态可以成为任何状态
    • 其他两种状态转化需要 x x x 点费用
  • S → T S \to T ST 的最短路
思路
  • D i j k s t r a Dijkstra Dijkstra (堆优化)
  • 图论最关键的是建图的方式,本题可以将状态为 M M M 的点拆分为两个状态分别为 L ,   R L, \ R L, R 的点
代码
#include <bits/stdc++.h>
using namespace std;
#define int long long
int T;
int n, m, s, t, x, u, v, val;
char str[200007];
vector<pair<int, int>> graph[200007]; // graph[fr] {to, val}
int dis[200007];
int cnt; // Nums of Node
int ans;

unordered_map<int, int> mp; // Node 'M' Divide into Double

void dijkstra(int st)
{
    priority_queue<pair<int, int>, vector<pair<int, int> >, greater<pair<int, int> > > que;
    // {dis[node], node}
    dis[st] = 0;
    que.push({dis[st], st});
    while (!que.empty())
    {
        int now = que.top().second;
        int tmpval = que.top().first;
        que.pop();
        if (dis[now] < tmpval)
            continue;
        for (int i = 0; i < graph[now].size(); i++)
        {
            int nxt = graph[now][i].first;
            int val = graph[now][i].second;
            int tmp = ((str[nxt] == str[now]) ? 0 : x);
            if (dis[nxt] > val + dis[now] + tmp)
            {
                dis[nxt] = val + dis[now] + tmp;
                que.push({dis[nxt], nxt});
            }
        }
    }
    return;
}

int32_t main(void)
{
    cnt = 0;
    scanf("%lld", &T);
    while (T--)
    {
        memset(dis, 0x3f, sizeof(dis));
        mp.clear();
        scanf("%lld%lld%lld%lld%lld", &n, &m, &s, &t, &x);
        scanf("%s", str + 1);
        for (int i = 1; i <= cnt; ++i)
            graph[i].clear();
        cnt = n;
        for (int i = 1; i <= m; ++i)
        {
            scanf("%lld%lld%lld", &u, &v, &val);
            // Build Map
            if (str[u] == 'M')
            {
                mp[u] = ++cnt;
                str[u] = 'L';
                str[mp[u]] = 'R';
                graph[u].push_back({mp[u], 0});
                graph[mp[u]].push_back({u, 0});
            }
            if (str[v] == 'M')
            {
                mp[v] = ++cnt;
                str[v] = 'L';
                str[mp[v]] = 'R';
                graph[v].push_back({mp[v], 0});
                graph[mp[v]].push_back({v, 0});
            }
            if (mp.count(u))
            {
                graph[mp[u]].push_back({v, val});
                graph[v].push_back({mp[u], val});
                if (mp.count(v))
                {
                    graph[mp[u]].push_back({mp[v], val});
                    graph[mp[v]].push_back({mp[u], val});
                }
            }
            if (mp.count(v))
            {
                graph[mp[v]].push_back({u, val});
                graph[u].push_back({mp[v], val});
            }
            graph[u].push_back({v, val});
            graph[v].push_back({u, val});
        }
        dijkstra(s);
        if (mp.count(s))
            dijkstra(mp[s]);
        // Incorrect Pos
        ans = dis[t];`
        if (mp.count(t))
            ans = min(ans, dis[mp[t]]);
        printf("%lld\n", ans);
    }
    return 0;
}
1012 Last Problem

链接:HDU6813 Last Problem

题意
  • 在平面点上填满足:

    n − 1 n - 1 n1
    n − 2 n - 2 n2 n n n n − 3 n - 3 n3
    n − 4 n - 4 n4
  • 输出构造方案,方案步骤数少于 1 e 5 1e5 1e5

思路
  • 构造 D F S DFS DFS
代码
#include <bits/stdc++.h>
using namespace std;

int T;
int n;
map<pair<int, int>, int> mp;
// canNot use Unordered Map
// Hash Function must be invocable with an argument of key type

void dfs(int x, int y, int n)
{
    if (n < 1) 
        return;
    if (mp[{x, y + 1}] != n - 1)
        dfs(x, y + 1, n - 1);
    if (mp[{x - 1, y}] != n - 2)
        dfs(x - 1, y, n - 2);
    if (mp[{x + 1, y}] != n - 3)
        dfs(x + 1, y, n - 3);
    if (mp[{x, y - 1}] != n - 4)
        dfs(x, y - 1, n - 4);
    mp[{x, y}] = n;
    cout << x << " " << y << " " << n << "\n";
}

int32_t main(void)
{
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cin >> n;
    mp.clear();
    dfs(0, 0, n);
    return 0;
}
1003 Contest of Rope Pulling

链接:HDU6804 Contest of Rope Pulling

题意
  • 背包容积 V V V

  • n + m n + m n+m 个物品,重量 w e i g h t i weight_i weighti 价值 v a l i val_i vali

  • n n n 个物品与 m m m 个物品中选择总重量相同的物品

  • 求这些物品价值的最大值

思路
  • m m m 件物品价值取 v a l i = − v a l i val_i = - val_i vali=vali,问题转化为普通的 01 01 01背包
  • 01 01 01背包 复杂度为 O ( ( n + m ) 2 ⋅ w e i g h t max ⁡ ) O((n + m) ^ {2} \cdot weight_{\max}) O((n+m)2weightmax) 显然会超时,但是本问题只需要 w e i g h t = 0 weight = 0 weight=0 时的 v a l max ⁡ val_{\max} valmax,故可以对物品随机化

如果我们以一种相对随机的方式安排物品的加入顺序,那么可以发现,最优解在每一阶段对应的状态都在 0 0 0 附近振荡。设最优解的子集为 S S S,在物品全集的加入顺序被等概率重排之后,子集 S S S 的加入顺 序也被等概率重排。我们只需要设一个足够大的上界 T T T,只考虑 [ − T , T ] [-T, T] [T,T] ∑ w e i g h t i \sum weight_i weighti,做原来的 D P DP DP 即可。

确实想不到背包可以这样做,本题与普通背包问题不同之处在于最终所需的 w e i g h t = 0 weight = 0 weight=0 在整个区间中间,故可以缩减 T T T 的值降低时间复杂度。

代码
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int MAXN = 1e5 + 7;

int T;
int n , m, w, v;
int len;
int ans;
int dp[MAXN];

struct Node
{
    int w, v;
}node[2007];

int32_t main(void)
{
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cin >> T;
    while (T--)
    {
        ans = 0;
        memset(dp, 0xBF, sizeof(dp));
        //0xBF= 10111111 = 191
        cin >> n >> m;
        for (int i = 1; i <= n; ++i)
        {
            cin >> w >> v;
            node[i] = {w, v};
        }
        for (int i = n + 1; i <= n + m; ++i)
        {
            cin >> w >> v;
            node[i] = {-w, v};
        }
        len = n + m;
        random_shuffle(node + 1, node + len + 1);
        // random_shuffle(node + 1, node + len + 1);
        dp[30000] = 0;
        for (int i = 1; i <= len; ++i)
        {
            if(node[i].w > 0)
            {
                for (int j = 60000; j >= node[i].w; --j)
                    dp[j] = max(dp[j], dp[j - node[i].w] + node[i].v);
            }
            else
            {
                for (int j = 0; j <= 60000 + node[i].w; ++j)
                    dp[j] = max(dp[j], dp[j - node[i].w] + node[i].v);
            }
            ans = max(ans, dp[30000]);
        }
        cout << ans << endl;
    }
    return 0;
}
1007 Go Running

链接:HDU6808 Go Running

题意
  • 给定参数 t t t x x x,求至少需要多少个匹配可以将平面上所有的 ( x , t ) (x, t) (x,t) 覆盖
  • 直线 t − x t - x tx t + x t + x t+x 上的点可以视作同一个点
思路
  • 二分图匹配
    • 二分图的最大匹配 = = = 二分图的最小点覆盖
    • H o − K a s h y a p Ho - Kashyap HoKashyap 算法
代码

(二分图匹配的相关算法还没有完全理解,先放一个套板子的代码)

#include <bits/stdc++.h>
using namespace std;
// #define int long long
const int MAXN = 5e5 + 7;
// const int MOD = ;
const int INF = 0x3f3f3f3f;
// const int DIRX[] = {};
// const int DIRY[] = {};

struct HK
{
    int cntx, cnty; // Num of Set 1 && Set 2
    vector<int> graph[MAXN]; // Edge Set 1 to Set 2
    int lnkx[MAXN], lnky[MAXN];
    int depx[MAXN], depy[MAXN]; // Depth
    bool vis[MAXN];
    int dep;

    bool bfs()
    {
        queue<int> q;
        dep = INF;
        memset(depx, -1, sizeof(depx));
        memset(depy, -1, sizeof(depy));
        memset(vis, 0, sizeof(vis));
        for (int i = 1; i <= cntx; ++i)
        {
            if (lnkx[i] == -1)
            {
                q.push(i);
                depx[i] = 0;
            }
        }
        while (!q.empty())
        {
            int now = q.front();
            q.pop();
            if (depx[now] > dep)
                break;
            for (int i = 0; i < graph[now].size(); ++i)
            {
                int nxt = graph[now][i];
                if (depy[nxt] == -1)
                {
                    depy[nxt] = depx[now] + 1;
                    if (lnky[nxt] == -1)
                        dep = depy[nxt];
                    else
                    {
                        depx[lnky[nxt]] = depy[nxt] + 1;
                        q.push(lnky[nxt]);
                    }
                }
            }
        }
        return dep != INF;
    }

    bool dfs(int now)
    {
        for (int i = 0; i < graph[now].size(); ++i)
        {
            int nxt = graph[now][i];
            if (!vis[nxt] && depy[nxt] == depx[now] + 1)
            {
                vis[nxt] = true;
                if(lnky[nxt] != -1 && depy[nxt] == dep)
                    continue;
                if(lnky[nxt] == -1 || dfs(lnky[nxt]))
                {
                    lnky[nxt] = now;
                    lnkx[now] = nxt;
                    return true;
                }
            }
        }
        return false;
    }

    int Ho_Kashyap()
    {
        int ans = 0;
        memset(lnkx, -1, sizeof(lnkx));
        memset(lnky, -1, sizeof(lnky));
        while (bfs())
        {
            for (int i = 1; i <= cntx; ++i)
            {
                if (lnkx[i] == -1 && dfs(i))
                    ans++;
            }
        }
        return ans;
    }
}hk;

unordered_map<int, int> mpx, mpy;
int T;
int n;
int t, x;
int rx, ry;
int cntx, cnty;

int32_t main(void)
{
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cin >> T;
    while (T--)
    {
        mpx.clear();
        mpy.clear();
        cntx = 0;
        cnty = 0;
        for (int i = 0; i <= 5e5; ++i)
            hk.graph[i].clear();
        cin >> n;
        for (int i = 1; i <= n; ++i)
        {
            cin >> t >> x;
            int rx = t + x;
            int ry = t - x;
            if (!mpx.count(rx))
                mpx[rx] = ++cntx;
            if (!mpy.count(ry))
                mpy[ry] = ++cnty;
            hk.graph[mpx[rx]].push_back(mpy[ry]);
        }
        hk.cntx = cntx;
        hk.cnty = cnty;
        cout << hk.Ho_Kashyap() << endl;
    }
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值