loj刷题记录2019/2/20

#10064. 「一本通 3.1 例 1」黑暗城堡

题目描述

你知道黑暗城堡有 NNN 个房间,MMM 条可以制造的双向通道,以及每条通道的长度。

城堡是树形的并且满足下面的条件:

DiD_iDi 为如果所有的通道都被修建,第 iii 号房间与第 111 号房间的最短路径长度;

SiS_iSi 为实际修建的树形城堡中第 iii 号房间与第 111 号房间的路径长度;

要求对于所有整数 iii (1≤i≤N1\le i\le N1iN),有 Si=DiS_i= D_iSi=Di 成立。

你想知道有多少种不同的城堡修建方案。当然,你只需要输出答案对 231−12^{31} -12311 取模之后的结果就行了。

输入格式

第一行为两个由空格隔开的整数 N,MN, MN,M;

第二行到第 M+1M+1M+1 行为 333 个由空格隔开的整数 x,y,lx, y, lx,y,l:表示 xxx 号房间与 yyy 号房间之间的通道长度为 lll。

输出格式

一个整数:不同的城堡修建方案数对 231−12^{31} -12311 取模之后的结果。

样例
样例输入
4 6
1 2 1
1 3 2
1 4 3
2 3 1
2 4 2
3 4 1
样例输出
6
样例说明

一共有 444 个房间,666 条道路,其中 111 号和 222 号,111 号和 333 号,111 号和 444 号,222 号和 333 号,222 号和 444 号,333 号和 444 号房间之间的通道长度分别为 111,222,333,111,222,111。

而不同的城堡修建方案数对 231−12^{31} -12311 取模之后的结果为 666。

先跑一次最短路,再将每一个点的方案数算出来,根据乘法远离相乘

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 const long long mod = (1 << 31) - 1;
 4 const int maxn = 1010;
 5 const int maxm = 1e6;
 6 int n, m, head[maxn], size, mp[maxn][maxn], dis[maxn];
 7 bool bj[maxn];
 8 long long ans = 1;
 9 struct edge {
10     int v, nex, w;
11 } e[maxm << 1];
12 
13 struct node {
14     int pos, cost;
15     node(int pos = 0, int cost = 0) : pos(pos), cost(cost) {}
16     friend bool operator<(node a, node b) { return a.cost > b.cost; }
17 };
18 
19 void adde(int u, int v, int w) {
20     e[size].v = v;
21     e[size].w = w;
22     e[size].nex = head[u];
23     head[u] = size++;
24 }
25 
26 void spfa() {
27     dis[1] = 0, bj[1] = 0;
28     priority_queue<node> q;
29     q.push(node(1, 0));
30     while (!q.empty()) {
31         node a = q.top();
32         q.pop();
33         bj[a.pos] = 0;
34         int u = a.pos;
35         for (int i = head[u]; ~i; i = e[i].nex) {
36             int v = e[i].v, w = e[i].w;
37             if (dis[v] > dis[u] + w) {
38                 dis[v] = dis[u] + w;
39                 if (!bj[v]) {
40                     bj[v] = 1;
41                     q.push(node(v, dis[v]));
42                 }
43             }
44         }
45     }
46 }
47 
48 int main() {
49     // freopen("in.txt","r",stdin);
50     memset(head, -1, sizeof(head));
51     memset(mp, 0x3f, sizeof(mp));
52     memset(dis, 0x3f, sizeof(dis));
53     scanf("%d%d", &n, &m);
54     for (int i = 1; i <= m; i++) {
55         int u, v, w;
56         scanf("%d%d%d", &u, &v, &w);
57         mp[u][v] = mp[v][u] = min(mp[u][v], w);
58         adde(u, v, w);
59         adde(v, u, w);
60     }
61     spfa();
62     for (int i = 2; i <= n; i++) {
63         long long cnt = 0;
64         for (int j = 1; j <= n; j++) {
65             if (mp[j][i] < 300 && dis[j] + mp[j][i] == dis[i])
66                 cnt++;
67         }
68         ans = (ans * cnt) % mod;
69         // printf("%d\n",ans);
70     }
71     printf("%lld", ans);
72     return 0;
73 }
View Code

 

「一本通 3.1 例 2」北极通讯网络

题目描述

原题来自:Waterloo University 2002

北极的某区域共有 nnn 座村庄,每座村庄的坐标用一对整数 (x,yx, yx,y) 表示。为了加强联系,决定在村庄之间建立通讯网络。通讯工具可以是无线电收发机,也可以是卫星设备。所有的村庄都可以拥有一部无线电收发机, 且所有的无线电收发机型号相同。但卫星设备数量有限,只能给一部分村庄配备卫星设备。

不同型号的无线电收发机有一个不同的参数 ddd,两座村庄之间的距离如果不超过 ddd 就可以用该型号的无线电收发机直接通讯,ddd 值越大的型号价格越贵。拥有卫星设备的两座村庄无论相距多远都可以直接通讯。

现在有 kkk 台卫星设备,请你编一个程序,计算出应该如何分配这 kkk 台卫星设备,才能使所拥有的无线电收发机的 ddd 值最小,并保证每两座村庄之间都可以直接或间接地通讯。

例如,对于下面三座村庄:

Picture1

其中 ∣AB∣=10,∣BC∣=20,∣AC∣=105≈22.36|AB|= 10, |BC|= 20, |AC|= 10\sqrt{5}≈22.36AB=10,BC=20,AC=105

22.36

如果没有任何卫星设备或只有 111 台卫星设备 (k=0k=0k=0 或 k=1k=1k=1),则满足条件的最小的 d=20d = 20d=20,因为 AAA 和 BBB,BBB 和 CCC 可以用无线电直接通讯;而 AAA 和 CCC 可以用 BBB 中转实现间接通讯 (即消息从 AAA 传到 BBB,再从 BBB 传到 CCC);

如果有 222 台卫星设备 (k=2k=2k=2),则可以把这两台设备分别分配给 BBB 和 CCC ,这样最小的 ddd 可取 101010,因为 AAA 和 BBB 之间可以用无线电直接通讯;BBB 和 CCC 之间可以用卫星直接通讯;AAA 和 CCC 可以用 BBB 中转实现间接通讯。

如果有 333 台卫星设备,则 A,B,CA,B,CA,B,C 两两之间都可以直接用卫星通讯,最小的 ddd 可取 000。

输入格式

第一行为由空格隔开的两个整数 n,kn,kn,k;

2∼n+12\sim n+12n+1 行,每行两个整数,第 iii 行的 xi,yix_i,y_ixi,yi 表示第 iii 座村庄的坐标 (xi,yix_i, y_ixi,yi)。

输出格式

一个实数,表示最小的 ddd 值,结果保留 222 位小数。

样例
样例输入
3 2
10 10
10 0
30 0
样例输出
10.00
数据范围与提示

 

即求最小生成树第k长的边

证明过程可参考  https://www.cnblogs.com/mxrmxr/p/9846958.html

先将dis数组的值初始化成与第一个借点的距离,即默认第一个点已在生成树上,在进行加边操作

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int maxn=505;
 4 int dis[maxn],n,k,x[maxn],y[maxn];
 5 bool vis[maxn];
 6 int cc(int a,int b){
 7     return (x[a]-x[b])*(x[a]-x[b])+(y[a]-y[b])*(y[a]-y[b]);
 8 }
 9 bool cmp(int a,int b){
10     return a>b;
11 }
12 int main(){
13     scanf("%d%d",&n,&k);
14     for(int i=1;i<=n;i++){
15         scanf("%d%d",x+i,y+i);
16         dis[i]=cc(1,i);
17     }
18     for(int i=1;i<n;i++){
19         int minn=1e9,pos;
20         for(int j=2;j<=n;j++) if(!vis[j]&&dis[j]<minn) minn=dis[pos=j];
21         vis[pos]=1;
22         for(int j=2;j<=n;j++) if(!vis[j]) dis[j]=min(dis[j],cc(j,pos));
23     }
24     sort(dis+1,dis+1+n,cmp);
25     printf("%.2f",sqrt(dis[k]));
26     return 0;
27 }
View Code

 

转载于:https://www.cnblogs.com/plysc/p/10408311.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值