2019ICPC南昌邀请赛现场赛A题 - Attack(斯坦纳树)

题意:

给出一张图,求让\(4\)对点相互可以到达的最小边权值。仅要求一对之间,一对与另外一对可到达也可不到达。

分析:

斯坦纳树裸题,众所周知斯坦纳树仅能求出这\(4\)对点(关键点)的连通状况,如这\(4\)对点相互都连通,某点和某点连通等。然而让这\(4\)对点连通符合题目要求,但不一定是最优解(我可以让每对点直接相连),所以我们要对斯坦纳树求出的\(dp\)数组进行子集\(dp\)才能得到最优解。

#include <bits/stdc++.h>
using namespace std;

const int N  = 50 + 5, M = 1000 + 5;
const int inf = 0x3f3f3f3f;

int n, m, w, tot, cnt, maxsta, head[N], vis[N];
int dp[N][1 << 10], ans[1 << 11];
string a, b;
queue<int> q;
map<string, int> maps;

struct node {
    int v, w, next;
} e[M << 1];

void init() {
    tot = cnt = 0;
    memset(dp, inf, sizeof dp);
    memset(head, 0, sizeof head);
    memset(vis, 0, sizeof vis);
    while (!q.empty()) q.pop();
    maps.clear();
}

void addedge(int u, int v, int w) {
    e[++cnt].v = v;
    e[cnt].w = w;
    e[cnt].next = head[u];
    head[u] = cnt;
}

void spfa(int sta) {
    while (!q.empty()) {
        int u = q.front();
        q.pop();
        vis[u] = 0;
        for (int i = head[u]; i; i = e[i].next) {
            int v = e[i].v, val = e[i].w;
            if (dp[v][sta] > dp[u][sta] + val) {
                dp[v][sta] = dp[u][sta] + val;
                if (!vis[v]) q.push(v), vis[v] = 1;
            }
        }
    }
}

bool check(int sta) {
    for (int i = 0; i < 8; i += 2) {
        if ((sta >> i & 1) ^ (sta >> (i + 1) & 1)) return false;
    }
    return true;
}

int main() {
    while (cin >> n >> m) {
        init();
        for (int i = 1; i <= n; i++) {
            cin >> a;
            maps[a] = ++tot;
        }
        for (int i = 1; i <= m; i++) {
            cin >> a >> b >> w;
            addedge(maps[a], maps[b], w);
            addedge(maps[b], maps[a], w);
        }
        for (int i = 0; i < 8; i++) {
            cin >> a;
            dp[maps[a]][1 << i] = 0;
        }
        maxsta = 1 << 8;
        for (int sta = 0; sta < maxsta; sta++) {
            while(!q.empty()) q.pop();
            for (int i = 1; i <= n; i++) {
                for (int s = sta; s; s = (s - 1) & sta) {
                    if(dp[i][sta] > dp[i][s] + dp[i][sta ^ s])
                        dp[i][sta] = dp[i][s] + dp[i][sta ^ s];
                }
                if(dp[i][sta] < inf) q.push(i), vis[i] = 1;
            }
            spfa(sta);
        }
        memset(ans, inf, sizeof ans);
        for (int s = 0; s < maxsta; s++) {
            if (!check(s)) continue;
            for (int i = 1; i <= n; i++) {
                ans[s] = min(ans[s], dp[i][s]);
            }
        }
        for (int s = 0; s < maxsta; s++) {
            if (!check(s)) continue;
            for (int p = (s - 1) & s; p; p = (p - 1) & s)
                ans[s] = min(ans[s], ans[p] + ans[s ^ p]);
        }
        cout << ans[maxsta - 1] << '\n';
    }
    return 0;
}

原文地址:https://www.cnblogs.com/ChaseNo1/p/11644939.html

时间: 2024-08-30 04:04:50

2019ICPC南昌邀请赛现场赛A题 - Attack(斯坦纳树)的相关文章

HDUOJ-------2493Timer(数学 2008北京现场赛H题)

Timer Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 445    Accepted Submission(s): 90 Problem Description Recently, some archaeologists discovered an ancient relic on a small island in the Pa

HDU 4791 Alice&#39;s Print Service(2013长沙区域赛现场赛A题)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4791 解题报告:打印店提供打印纸张服务,需要收取费用,输入格式是s1 p1 s2 p2 s3 p3...表示打印区间s1到s2张纸的单价是p1,打印区间s2 到s3的单价是p2....最后是sn到无穷大的单价是pn,让你求打印k张纸的总费用最少是多少?有m次查询. 因为s1*p1 > s2 * p2 > s3*p3......,很显然,加入k所在的那个区间是第x个区间,那么最低费用要么是k * p

zoj 3819(牡丹江现场赛A题)

马上要去上海了,刷刷现场赛的题找找感觉~~~ 这题.......额,没什么好说的,太水.. ZOJ Problem Set - 3819 Average Score Time Limit: 2 Seconds      Memory Limit: 65536 KB Bob is a freshman in Marjar University. He is clever and diligent. However, he is not good at math, especially in Mat

2013 ACM/ICPC 长沙现场赛 A题 - Alice&#39;s Print Service (ZOJ 3726)

Alice's Print Service Time Limit: 2 Seconds      Memory Limit: 65536 KB Alice is providing print service, while the pricing doesn't seem to be reasonable, so people using her print service found some tricks to save money. For example, the price when

HDU 4119 Isabella&#39;s Message (2011年成都赛区现场赛I题)

1.题目描述:点击打开链接 2.解题思路:本题是一道模拟题,要求模拟一个解密的过程,练习这么久第一次做模拟题1Y了,内心还是很激动的~.只需要根据题意,记录* 所在的位置即可,然后每次都是先解密,后顺时针旋转90度.把每次解密的信息放到一个vector里,接下来就是连接它们,得到解密后的字符串,在map中查找这些单词是否存在即可.如果都存在,就把这条解密信息放到ans中,最后对ans排序,输出ans[0]就是答案. 3.代码: //#pragma comment(linker, "/STACK:

HDUOJ--------A simple stone game(尼姆博弈扩展)(2008北京现场赛A题)

A simple stone game                                                                                                       Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)                                             

HDU 4815 2013长春现场赛C题

C - Little Tiger vs. Deep Monkey Time Limit:1000MS     Memory Limit:65535KB     64bit IO Format:%I64d & %I64u Submit Status Practice HDU 4815 Description A crowd of little animals is visiting a mysterious laboratory ? The Deep Lab of SYSU. "Are y

南昌邀请赛网络赛 D.Match Stick Game(dp)

南昌邀请赛网络赛 D.Match Stick Game 题目传送门 题目就会给你一个长度为n的字符串,其中\(1<n<100\).这个字符串是一个表达式,只有加减运算符,然后输入的每一个字符都是可以由若干个火柴棒拼接而成的. 现在在不改变每个数的位数,数的总数以及运算符的个数的前提下,可以对火柴棒重新拼接.询问最后可以拼接出来的最大值是多少. 这个自己看下题目可能要清楚一些= = ? 每一个字符都是由若干个火柴棒构成的,我们可以考虑类似于背包的思路来求解. 因为每个数的位数最后都没发生变化,所

FJoi2017 1月20日模拟赛 直线斯坦纳树(暴力+最小生成树+骗分+人工构造+随机乱搞)

[题目描述] 给定二维平面上n个整点,求该图的一个直线斯坦纳树,使得树的边长度总和尽量小. 直线斯坦纳树:使所有给定的点连通的树,所有边必须平行于坐标轴,允许在给定点外增加额外的中间节点. 如下图所示为两种直线斯坦纳树的生成方案,蓝色点为给定的点,红色点为中间节点. [输入格式] 第一行一个整数n,表示点数. 以下n行,每行两个整数表示点的x,y坐标. [输出格式] 第一行一个整数m,表示中间节点的个数. 必须满足m <= 10 * n 以下m行,每行2个整数表示中间节点的坐标. 以下n+m-1