• noip2017day2


    P3958 奶酪

    输入输出样例

    输入样例#1: 复制
    3 
    2 4 1 
    0 0 1 
    0 0 3 
    2 5 1 
    0 0 1 
    0 0 4 
    2 5 2 
    0 0 2 
    2 0 4
    输出样例#1: 复制
    Yes
    No
    Yes

    说明

    题解:广搜或并查集

    #include <bits/stdc++.h>
    
    using namespace std;
    const int maxn = 1005;
    #define ll long long
    ll x[maxn], y[maxn], z[maxn], tot;
    bool vis[maxn];
    int h[maxn];
    void read(ll &x){
        ll f=1;x=0;char c=getchar();
        while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
        x*=f;
    }
    void init(){
        memset(vis, 0, sizeof(vis));
        memset(h, 0, sizeof(h));
        tot = 0;
    }
    struct edge{int v, nxt;}G[maxn*maxn];
    void add(int u, int v){
        G[++tot].nxt = h[u]; G[tot].v = v; h[u] = tot;
        G[++tot].nxt = h[v]; G[tot].v = u; h[v] = tot;
    }
    void bfs(){
        queue <int> Q;
        Q.push(0);
        vis[0] = 1;
        while(!Q.empty()){
            int u = Q.front(); Q.pop();
            for(int i = h[u]; i; i = G[i].nxt){
                int v = G[i].v;
                if(!vis[v]){Q.push(v); vis[v] = 1;}
            }
        }
    }
    bool adjoint(int i, int j, ll r){
        long double t = (long double)((x[i]-x[j])*(x[i]-x[j]) + (y[i]-y[j])*(y[i]-y[j]) + (z[i]-z[j])*(z[i]-z[j]));
        return t <= 4*r*r;
    
    }
    int main()
    {
        //freopen("cheese.in","r",stdin);
        //freopen("cheese.out","w",stdout);
        int T;
        scanf("%d",&T);
        while(T--){
            int n; ll h, r;
            scanf("%d",&n);
            read(h), read(r);
            init();
            for(int i = 1; i <= n; i++)read(x[i]), read(y[i]), read(z[i]);
            for(int i = 1; i <= n; i++){
                if(z[i] - r <= 0)add(i, 0);
                if(z[i] + r >= h)add(n+1, i);
                for(int j = i+1; j <= n; j++)
                    if(adjoint(i, j, r))add(i, j);
            }
            bfs();
            if(vis[n+1])puts("Yes");
            else puts("No");
        }
        return 0;
    }
    View Code

     P3959 宝藏

    题目描述

    参与考古挖掘的小明得到了一份藏宝图,藏宝图上标出了 nn 个深埋在地下的宝藏屋, 也给出了这 nn 个宝藏屋之间可供开发的 mm 条道路和它们的长度。

    小明决心亲自前往挖掘所有宝藏屋中的宝藏。但是,每个宝藏屋距离地面都很远, 也就是说,从地面打通一条到某个宝藏屋的道路是很困难的,而开发宝藏屋之间的道路 则相对容易很多。

    小明的决心感动了考古挖掘的赞助商,赞助商决定免费赞助他打通一条从地面到某 个宝藏屋的通道,通往哪个宝藏屋则由小明来决定。

    在此基础上,小明还需要考虑如何开凿宝藏屋之间的道路。已经开凿出的道路可以 任意通行不消耗代价。每开凿出一条新道路,小明就会与考古队一起挖掘出由该条道路 所能到达的宝藏屋的宝藏。另外,小明不想开发无用道路,即两个已经被挖掘过的宝藏 屋之间的道路无需再开发。

    新开发一条道路的代价是: L* K

    L代表这条道路的长度,K代表从赞助商帮你打通的宝藏屋到这条道路起点的宝藏屋所经过的 宝藏屋的数量(包括赞助商帮你打通的宝藏屋和这条道路起点的宝藏屋) 。

    请你编写程序为小明选定由赞助商打通的宝藏屋和之后开凿的道路,使得工程总代 价最小,并输出这个最小值。

    输入输出格式

    输入格式:

    第一行两个用空格分离的正整数 n,mn,m ,代表宝藏屋的个数和道路数。

    接下来 mm 行,每行三个用空格分离的正整数,分别是由一条道路连接的两个宝藏 屋的编号(编号为 1-n1n),和这条道路的长度 vv 。

    输出格式:

    一个正整数,表示最小的总代价。

    输入输出样例

    输入样例#1: 复制
    4 5 
    1 2 1 
    1 3 3 
    1 4 1 
    2 3 4 
    3 4 1 
     
    输出样例#1: 复制
    4
    输入样例#2: 复制
    4 5 
    1 2 1 
    1 3 3 
    1 4 1 
    2 3 4 
    3 4 2  
    输出样例#2: 复制
    5

    说明

    题解:状压dp, 方程很简单,但实现起来很多细节

    dp[s][j] 表示经过了那些地方s,  j表示现在停在那里;

    dp[s][i] = max(dp[s^i][j] + mp[j][i] * dis[s^i][j]); dis表示在当前状态下,j离根的距离; O(2^n * n^2) 

    注意: 当dis[s][ i ] 更新完以后,其他的dis[s][ ] 也要复制一下,最开始忘了;

    #include <bits/stdc++.h>
    
    using namespace std;
    const int inf = 1000000008, maxn = 1<<14;
    
    int dp[maxn], sta[maxn][15], mp[15][15];
    bool inq[15];
    int n, m, ans = inf;
    
    void init(){
        memset(dp, 127, sizeof(dp));
        memset(sta, 127, sizeof(sta));
    }
    
    void read(int &x){
        int f=1;x=0;char c=getchar();
        while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
        x*=f;
    }
    int main()
    {
      // freopen("treasure.in","r",stdin);
       // freopen("treasure.out","w",stdout);
        scanf("%d%d",&n, &m);
        memset(mp, 127, sizeof(mp));
        for(int i = 1; i <= m; i++){
            int u, v, w;
            read(u), read(v), read(w);
            if(mp[u][v] > w)mp[u][v] = mp[v][u] = w;
        } 
        for(int st = 1; st <= n; st++){
            init();
            dp[1<<(st-1)] = 0;
            for(int s = 1<<(st-1); s < (1<<n); s++){
                if((s&(1<<(st-1))) == 0)continue;
                sta[s][st] = 1;
                for(int i = 1; i <= n; i++)
                    if((s&(1<<(i-1))) == 0)
                        for(int j = 1; j <= n; j++)//gao wei
                            if(s&(1<<(j-1)) && mp[j][i] < inf && sta[s][j] < inf){
                                int t = dp[s] + sta[s][j] * mp[j][i];
                                if(t < dp[s|(1<<(i-1))]){
                                    dp[s|(1<<(i-1))] = t;
                                    for(int p=1;p<=n;p++)
                                       sta[s|(1<<(i-1))][p] = sta[s][p];
                                    sta[s|(1<<(i-1))][i] = sta[s][j] + 1;
                                    
                                }
                            }
            }
          //  if(st == 3) for(int s = 1; s <(1<<n); s++)printf("dp[%d] = %d
    ",s,dp[s]);
        //    cout<<dp[(1<<n)-1]<<" "<<st<<endl;
            ans = min(ans, dp[(1<<n)-1]);
        }
       
        printf("%d
    ",ans);
        return 0;
    }
    View Code

    dfs版,不用复制,跑的快一些;

    #include <bits/stdc++.h>
    
    using namespace std;
    const int inf = 1000000008, maxn = 1<<14;
    
    int dp[maxn], dis[15], mp[15][15];
    bool inq[15];
    int n, m, ans = inf;
    
    void init(){
        memset(dp, 127, sizeof(dp));
        memset(dis, 0, sizeof(dis));
    }
    void dfs(int s){
        for(int i = 1; i <= n; i++){
            if(s&(1<<(i-1)))continue;
            for(int j = 1; j <= n; j++)
            if(s&(1<<(j-1)) && mp[i][j] < inf){
                int t = dp[s] + dis[j] * mp[i][j];
                if(t < dp[s|(1<<(i-1))]){
                    int tmp = dis[j];
                    dis[i] = dis[j] + 1;
                    dp[s|(1<<(i-1))] = t;
                    dfs(s|(1<<(i-1)));
                    dis[i] = tmp;
                }
            }
        }
    }
    void read(int &x){
        int f=1;x=0;char c=getchar();
        while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
        x*=f;
    }
    int main()
    {
        //freopen("treasure.in","r",stdin);
        //freopen("treasure.out","w",stdout);
        scanf("%d%d",&n, &m);
        memset(mp, 127, sizeof(mp));
        for(int i = 1; i <= m; i++){
            int u, v, w;
            read(u), read(v), read(w);
            if(mp[u][v] > w)mp[u][v] = mp[v][u] = w;
        }
        for(int st = 1; st <= n; st++){
            init();
            dp[1<<(st-1)] = 0;
            dis[st] = 1;
            dfs(1<<(st-1));
            ans = min(ans, dp[(1<<n)-1]);
            //cout<<" "<<dp[(1<<n)-1]<<" "<<st<<endl;
        }
        printf("%d
    ",ans);
        return 0;
    }
    View Code

    P3953 逛公园

    输入输出样例

    输入样例#1: 复制
    2
    5 7 2 10
    1 2 1
    2 4 0
    4 5 2
    2 3 2
    3 4 1
    3 5 2
    1 5 3
    2 2 0 10
    1 2 0
    2 1 0
    输出样例#1: 复制
    3
    -1
    
    

    说明

    题解:dp, dp[u][k]表示现在在u这个节点,还有k可以拿去随便挥霍的方案数;

    dp[u][k] += dp[v][ k + dis[v] - dis[u] + G[i].w ], dis是到1的最短路,然后枚举k,dfs;

    两个地方:由于可以跑回去所以不能在终点设置边界;多放一个虚点,用来设置边界;

    对于无限跑环的是因为有0边存在,不然总会停的,跑0边的条件是从dp[u][k] 又跑到dp[u][k], 所以用一个ins来记录状态,防止死循环

    #include <bits/stdc++.h>
    
    using namespace std;
    int n,m,k,p,tot,tot2;
    const int maxn = 100005, inf = 2000000008;
    const int  maxm = maxn*2;
    int dis[maxn],hh[maxn],h[maxn],dp[maxn][55];
    bool vis[maxn],inq[maxn],ins[maxn][55];
    struct edge{int v,w,nxt;}G[maxm],g[maxm];
    struct Node{
        int v, dis;
        bool operator < (const Node &a)const{
            return dis > a.dis;
        }
    };
    void dij(){
        priority_queue <Node> q;
        q.push(Node{n+1, 0});
        memset(dis, 127, sizeof(dis));
        memset(vis, 0, sizeof(vis));
        dis[n+1] = 0;
        while(!q.empty()){
            Node u = q.top(); q.pop();
            if(vis[u.v])continue;
            vis[u.v] = 1;
    
            for(int i = hh[u.v]; i; i = g[i].nxt){
                int v = g[i].v;
                if(!vis[v] && dis[v] > dis[u.v] + g[i].w){
                    dis[v] = dis[u.v] + g[i].w;
                    q.push(Node{v, dis[v]});
                }
            }
        }
    }
    int dfs(int u, int kk){
        if(ins[u][kk])return inf;
        if(dp[u][kk] != -1)return dp[u][kk];
        ins[u][kk] = 1;
        dp[u][kk] = 0;
        for(int i = h[u]; i; i = G[i].nxt){
            int v = G[i].v;
            int pp = dis[u] + kk - dis[v] - G[i].w;
            if(pp < 0)continue;
            if(dfs(v, pp) == inf)return dp[u][kk] = inf;
            dp[u][kk] = (dp[u][kk] + dp[v][pp]) % p;
        }
        ins[u][kk] = 0;
        return dp[u][kk];
    
    }
    void add2(int u,int v,int w){G[++tot2].nxt=h[u];G[tot2].v=v;G[tot2].w=w;h[u]=tot2;}
    void add1(int u,int v,int w){g[++tot].nxt=hh[u];g[tot].v=v;g[tot].w=w;hh[u]=tot;}
    void init(){
        memset(h,0,sizeof(h));
        memset(hh,0,sizeof(hh));
        memset(ins, 0, sizeof(ins));
        tot = tot2 = 0;
        for(int i = 0; i <= k; i++)
            for(int j = 1; j <= n; j++)dp[j][i] = -1;
        for(int i = 1; i <= k; i++) dp[n+1][i] = 0;
        dp[n+1][0] = 1;
    }
    int main()
    {
        int t;
        scanf("%d",&t);
        while(t--){
    
            scanf("%d%d%d%d",&n,&m,&k,&p);
            init();
            for(int i = 1; i <= m; i++){
                int u,v,w;
                scanf("%d%d%d",&u,&v,&w);
                add2(u, v, w);
                add1(v, u, w);
            }
            add1(n+1, n, 0);add2(n, n+1, 0);
            dij();
            int ans = 0;
            for(int i = 0; i <= k; i++){
                int t = dfs(1, i);
                if(t == inf){ans = -1; break;}
                ans = (ans + t) % p;
            }
            printf("%d
    ",ans);
    
        }
    
        return 0;
    }
    View Code
  • 相关阅读:
    MyEclipse快捷键大全
    mac下配置android环境变量
    JAVA NIO 简单介绍
    android读取大图片并缓存
    Android  <meta-data>
    iPhone 6/6 Plus国行版开卖当日抢购攻略
    A380上11万一张的机票什么享受?来看看
    连载15年!《火影忍者》终于迎来大结局
    Windows 技术预览版
    纪录片《天安门》
  • 原文地址:https://www.cnblogs.com/EdSheeran/p/9457397.html
Copyright © 2020-2023  润新知