2020牛客暑期多校训练营(第五场)

比赛链接

A

一、题意

n个点m条带权边的无向连通图。边权就是距离。

初始时你在点1,让你依次经过2*k个点,使总距离最小。

定义一个瞬移方式:

(1)你可以从一个传送门花费0距离到达另一个传送门。

(2)初始时每个点都有一个关闭的传送门。

(3)你可以在任何一个点关闭任何一个传送门。

(4)你只能打开当前点的传送门。

(5)同时最多存在两个开启的传送门。

数据范围:n,k\leqslant 300

二、题解

只关注一个传送门的位置即可,因为我们可以在需要的时候在当前位置开启一个传送门,到达另一个传送门。

dp[i][j]表示到达第i个点时其中一个传送门在j。

转移方式在注释中,就是把ppt的题解模拟了一下。

三、代码

#include
#define pb push_back
#define fi first
#define se second
#define sz(x)  (int)x.size()
#define cl(x)  x.clear()
#define all(x)  x.begin() , x.end()
#define rep(i , x , n)  for(int i = x ; i <= n ; i ++)
#define per(i , n , x)  for(int i = n ; i >= x ; i --)
#define mem0(x)  memset(x , 0 , sizeof(x))
#define mem_1(x)  memset(x , -1 , sizeof(x))
#define mem_inf(x)  memset(x , 0x3f , sizeof(x))
#define debug(x)  cerr << '*' << x << '\n'
#define ddebug(x , y)  cerr << '*' << x << ' ' << y << '\n'
#define ios std::ios::sync_with_stdio(false) , cin.tie(0)
using namespace std ;
typedef long long ll ;
typedef long double ld ;
typedef pair pii ;
typedef pair pll ;
const int mod = 998244353 ;
const int maxn = 300 + 10 ;
const int inf = 0x3f3f3f3f ;
const double eps = 1e-6 ; 
mt19937  rnd(chrono::high_resolution_clock::now().time_since_epoch().count()) ; 
int n , m , p ;
int c[maxn << 1] ;
ll dis[maxn][maxn] ;
ll dp[maxn << 1][maxn] ;
int main()
{
    ios ;
    cin >> n >> m >> p ;
    mem_inf(dis) ;
    mem_inf(dp) ;
    rep(i , 1 , m)
    {
        int u , v ;
        ll w ;
        cin >> u >> v >> w ;
        dis[u][v] = min(dis[u][v] , w) ;
        dis[v][u] = min(dis[v][u] , w) ; 
    }
    rep(i , 1 , n)  dis[i][i] = 0ll ;
    rep(k , 1 , n)  rep(i , 1 , n)  rep(j , 1 , n)  dis[i][j] = min(dis[i][j] , dis[i][k] + dis[k][j]) ;
    p = p * 2 ;
    rep(i , 1 , p)  cin >> c[i] ;
    dp[0][1] = 0 ;
    c[0] = 1 ;
    rep(i , 0 , p - 1)  rep(j , 1 , n)
    {
        //1.直接从c[i]走到c[i+1]
        dp[i + 1][j] = min(dp[i + 1][j] , dp[i][j] + dis[c[i]][c[i + 1]]) ;
        //2.枚举走到c[i+1]之后,传送门的位置变为了哪个节点,设这个节点是k。第二种转移是从c[i]走到k,在k设置传送门,从k传送到j,再从j走到c[i+1]
        rep(k , 1 , n)  dp[i + 1][k] = min(dp[i + 1][k] , dp[i][j] + dis[c[i]][k] + dis[j][c[i + 1]]) ;
        //3.第三种转移是从c[i]传送到j,从j走到k,在k设置传送门,最后从k走到c[i+1]
        rep(k , 1 , n)  dp[i + 1][k] = min(dp[i + 1][k] , dp[i][j] + dis[j][k] + dis[k][c[i + 1]]) ;
    }
    ll ans = 1e18 ;
    rep(i , 1 , n)  ans = min(ans , dp[p][i]) ;
    cout << ans << '\n' ;
    return 0 ;
}

B

一、题意

二、题解

三、代码

C

一、题意

二、题解

三、代码

D

一、题意

二、题解

三、代码

E

一、题意

二、题解

三、代码

F

一、题意

二、题解

三、代码

G

一、题意

二、题解

三、代码

H

一、题意

二、题解

三、代码

I

一、题意

二、题解

三、代码

J

一、题意

二、题解

三、代码

K

一、题意

二、题解

三、代码

 

你可能感兴趣的:(#,2020牛客多校)