【牛客练习赛17】 A E【最短路 + 枚举 】

A长方体

链接:https://www.nowcoder.com/acm/contest/109/A
来源:牛客网

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld
题目描述
给出共享长方体一个顶点的三个面的面积,求它十二条边的边长和。
输入描述:
一行三个整数a, b, c表示面积(1 <= a, b, c <= 10000)。
输出描述:
一行一个整数表示边长和。
示例1
输入
1 1 1
输出
12
示例2
输入
4 6 6
输出
28
代码

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <vector>
using namespace std;

typedef long long ll;
typedef unsigned long long ull;

const int N = (int) 10000 + 11;
const int M = (int) 1e6 + 11;
const int mod = (int) 1e9 + 7;
const int INF =  0x3f3f3f3f;

int main(){
    int a, b, c;
    scanf("%d%d%d", &a, &b, &c);
    for(int i = 1; i <= N; i++){
        for(int j = 1; j <= N; j++){
            if(i * j != a) continue;
            for(int k = 1; k <= N; k++){
                if(i * k == b && j * k == c){
                    printf("%d\n",(i + j + k) * 4);
                    return 0;
                }
            }
        }
    }
return 0;
}

E 求长度

链接:https://www.nowcoder.com/acm/contest/109/E
来源:牛客网

时间限制:C/C++ 3秒,其他语言6秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld
题目描述
给定一幅n个点m条边的图和S个一定要经过的点,问从0号点出发,经过这S个点再回到0号点的最短路径长度是多少。
输入描述:
第一行一个整数T(T <= 2)表示数据组数。
对于每组数据,第一行两个整数n,m表示点数和边数(1 <= n, m <= 100,000)。
接下来m行,每行三个整数x, y, z(0 < x, y < n, 0 <= z <= 1000)表示xy之间有一条长度为c的双向边;
接下来一个整数S。(S<=10)
接下来S行每行一个整数表示一定要经过的点。
数据保证有解。
输出描述:
T行,每行一个整数表示答案。
示例1
输入
1
4 6
0 1 1
1 2 1
2 3 1
3 0 1
0 2 5
1 3 5
3
1
2
3
输出
4

分析: 一开始看 感觉很像 优先队列的BFS + 状态压缩 (感觉和之前做的很像),但是却无限WA, 好吧, 通过这次,我明白了, 状态压缩 不能够加 优先队列的BFS,如果每次移动都是相同距离,那么就可以用了。
就比如下面这个数据 就过不了。
1
4 6
0 1 1
1 2 1
2 3 1
3 0 1
0 2 5
1 3 5
2
2
3
出问题的点: 到达 2这个点的时候,一定是最短的,而且状态正好是满的(走完了所有关键点),但是它却有一条边直接走向了0,但是最短的路径却不是这个。
状压 + BFS的错误代码

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

const int N = (int) 1e5 + 11;
const int M = (int) 1e6 + 11;


struct Node{
     int id, step, state;
    Node(){}
    Node(int _id, int _step, int _state){
        id = _id; step = _step; state = _state;
    }
    friend bool operator < (Node a, Node b){
        return a.step > b.step;
    }
};


struct Edge{
    int from, to, val, next;
    Edge(){}
    Edge (int _from, int _to, int _val, int _next){
        from = _from; to = _to; val = _val; next = _next;
    }
}edge[N * 2 + 1];
int head[N + 1], top;  int n, m, ss;
void init(){
    memset(head, -1, sizeof(int) * (n + 1));
    top = 0;
}
void Addedge(int a, int b, int c){
    edge[top] = Edge(a, b, c, head[a]);
    head[a] = top++;
    edge[top] = Edge(b, a, c, head[b]);
    head[b] = top++;
}
void getmap(){
    int a, b, c;
    while(m--){
        scanf("%d%d%d", &a, &b, &c);
        Addedge(a, b, c);
    }
}

bool vis[N + 1][(1 << 11)];
map <int, int> ID;  int full;
int BFS(){
    memset(vis, false, sizeof(vis));
    priority_queue <Node> que;
    que.push(Node(0, 0, 0)); //vis[0][0] = 1;

    while(!que.empty()){
        Node now = que.top(); que.pop();
       // printf("@@@ %d %d %d \n", now.id, now.step, now.state);
        if(now.id == 0 &&  now.state == full){
            return now.step;
        }
        for(int i = head[now.id]; i != -1; i = edge[i].next){
            Edge e = edge[i];
            if(vis[e.to][now.state] == 1) continue;
            vis[e.to][now.state] = 1;
            int sta = now.state;
            if(ID[e.to] != 0) sta = now.state | (1 << (ID[e.to] - 1));
            que.push(Node(e.to, now.step + e.val, sta));
        }
    }
    return -1;
}

int main(){
    int T; scanf("%d", &T);
    while(T--){
        scanf("%d%d", &n, &m);
        init();
        getmap();
        scanf("%d", &ss);
        ID.clear(); full = 0;
        for(int i = 0; i < ss; i++) {
            int tmp; scanf("%d", &tmp);
            ID[tmp] = i + 1;
            full |= (1 << i);
        }
       // printf("%d \n", full);
        printf("%d\n", BFS());
    }
return 0;
}

正解: 思路写在了代码中:

代码

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

const int N = (int) 1e5 + 11;
const int M = (int) 1e6 + 11;

struct Edge{
    int from, to, val, next;
    Edge(){}
    Edge (int _from, int _to,  int _val, int _next){
        from = _from; to = _to; val = _val; next = _next;
    }
}edge[N * 2 + 1];
int head[N + 1], top;  int n, m, ss;
void init(){
    memset(head, -1, sizeof(int) * (n + 1));
    top = 0;
}

void Addedge(int a, int b, int c){
    edge[top] = Edge(a, b, c, head[a]);
    head[a] = top++;
}

bool vis[N + 1]; int Dis[N + 1];
int SPFA(int s,int t){
    memset(Dis, 0x3f, sizeof(int) * (n + 1));
    memset(vis, false, sizeof(bool) * (n + 1));
    vis[s] = true; Dis[s] = 0;
    queue<int> que; que.push(s);
    while(!que.empty()){
        int now = que.front(); que.pop(); vis[now] = false;
        for(int i = head[now]; i != -1; i = edge[i].next){
            Edge e = edge[i];
            if(Dis[e.to] > Dis[now] + e.val) {
                Dis[e.to] = Dis[now] + e.val;
                if(!vis[e.to]){
                    que.push(e.to);
                    vis[e.to] = true;
                }
            }
        }
    }
    return Dis[t];
}

int dis[20][20], p[20];
int Solve(){
    int a, b, c;
    while(m--){
        scanf("%d%d%d", &a, &b, &c);
        Addedge(a, b, c);
        Addedge(b, a, c);
    }

    int ss; scanf("%d", &ss);
    p[0] = 0;
    for(int i = 1; i <= ss; i++ ) scanf("%d", &p[i]);

    memset(dis, 0x3f, sizeof(dis));
    for(int i = 0; i <= ss; i++) {  // 得到任意两个关键点之间的最短路
        for(int j = 0; j <= ss; j++){
            dis[i][j] = SPFA(p[i], p[j]);
        }
    }

    Dis[0] = 0;
    for(int i = 1; i <= ss; i++) Dis[i] = i;
    int ans  = 0x3f3f3f3f;

    do{  // 遍历所有 可以访问到所有关键点的 顺序 
        int sum = dis[Dis[ss]][Dis[0]];
        for(int i = 1; i <= ss; i++)
            sum += dis[Dis[i-1]][Dis[i]];
        if(sum < ans) ans = sum;
    }while(next_permutation(Dis + 1, Dis + ss + 1)) ;

    return ans;
}

int main(){
    int T; scanf("%d", &T);
    while(T--){
        scanf("%d%d", &n, &m);
        init();
        printf("%d\n", Solve());
    }
return 0;
}

/*


200
4 6
0 1 1
1 2 1
2 3 1
3 0 1
0 2 5
1 3 5
1
1


*/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值