巨额奖金 Award
来源:互联网 发布:程序员求职简历怎么写 编辑:程序博客网 时间:2024/04/30 07:38
巨额奖金
Award/.IN/.OUT/.PAS/.EXE
问题描述
NJ 市的快速发展得益于其便捷的交通。可是,随着经济的发展,大量的人进入NJ 市,
NJ 市的交通也承受着巨大的压力。现在,NJ 市正在筹划建设一个新型的交通枢纽,从而
减轻交通的压力。
NJ 市包含n 个区,有些区之间有双向的干道存在。新型交通枢纽建设在这些干道的基
础上,将其中的部分干道改进为新型干道。改进后,干道能承受的压力可以比原来增加几十
倍。为了和谐发展,在新型的交通枢纽建成后,要求任何两个区之间都可以只通过新型干道
(直接或间接地)连接。政府已经预测出每条干道改进为新型干道的费用。政府希望建设新
型交通枢纽的总费用最小,并以巨额奖金向市民征集方案。政府很快发现费用最小的方案不
一定唯一,所以决定将奖金平分给每一种方案的第一个设计者,即如果一个人设计的费用是
最小的而且前面没人和他设计出一模一样的方案,则他可获奖。
栋栋被奖金深深的吸引,准备设计一种方案。可是,他发现方案可能会很多,如果最后
获奖者太多,巨额的资金分到每个人头上的也不会太多。所以他决定先算一下可行的方案数
是多少。
输入
输入的第一行包含两个数n (1 ≤ n ≤ 100),m (1 ≤ m ≤ 1,000),分别表示该市有
多少个区和有多少条干道。接下来m 行,每行三个数ai、bi、ci (1 ≤ ai, bi ≤ n, 1 ≤ ci ≤
1,000,000,000),表示ai 区和bi 区之间有一条干道,如果改进需要ci 的费用。
输入保证任何两个区之间至多有一条干道。对于任何一个费用c,不会有超过10 条干
道的费用都是c。
输出
输出费用最小的方案有多少种。由于答案可能很大,你只要输出方案数除以31011 的
模即可。
具体来说,就是求图的最小生成树个数
做法是先生成一遍最小生成树,记录树中各种权值的边有多少个
然后得出考虑这些边的生成树个数
某论文上有讲基尔霍夫矩阵求生成树个数的方法,十分高端
对于这道题,同一费用边不超过10个
则所以重新做一遍prim,
对于每种权值不同的边进行一遍搜索看有多少种可行解
乘起来以后随意找一种方案合并,继续寻找下一种权值不同的边
证明虽觉屌,但不明
证明:
我们用反证法来证明:假如对于图G的某一个最小生成树,其子图Gi不是一棵树,而是若干个连通块,那么由于图G是连通的,所以我们可以确定Gi中的连通块必然通过若干条其他边连起来。那么此时我们将子图中某条可以将两个连通块连接起来的边加入图中(这条边必定可以找到,因为图G’中,Gi为连通分量),这样图G的最小生成树就会形成一个环,并且这个环上必定有权值比c大的边(因为必定有边将Gi与其他子图连接起来),这时我们去掉权值比c大的边,可以得到一颗新的生成树,而且这颗生成树比最小生成树还要小,这样就产生了矛盾。
program award;type lin=record u,v,c:longint; end;const maxn=31011;var can:boolean; now,ans,count,s,tot,n,m,i,j,k,x,y:longint; line:array [0..1001] of lin; cop,father,dl:array [0..101] of longint;procedure swap (var a,b:lin);var i:lin;begin i:=a; a:=b; b:=i;end;procedure qsort (s,e:longint);var i,j,k:longint;begin if s>=e then exit; i:=s; j:=e; k:=line[(s+e) div 2].c; while i<=j do begin while line[i].c<k do inc(i); while line[j].c>k do dec(j); if i>j then break; swap(line[i],line[j]); inc(i); dec(j); end; qsort(s,j); qsort(i,e);end;function root (now:longint):longint;begin if father[now]=0 then exit(now); father[now]:=root(father[now]); exit(father[now]);end;function mother (now:longint):longint;begin if father[now]=0 then exit(now); exit(mother(father[now]));end;procedure search (k,s,e,left:longint);var i,x,y:longint;begin if k>e then begin if not can then begin cop:=father; can:=true; end; inc(now); exit; end; if e-k+1>left then search(k+1,s,e,left); if left>0 then begin x:=mother(line[k].u); y:=mother(line[k].v); if x=y then exit; father[y]:=x; search(k+1,s,e,left-1); father[y]:=0; end;end;begin assign(input,'award.in'); reset(input); assign(output,'award.out'); rewrite(output); read(n,m); if m<n-1 then begin writeln(0); close(input); close(output); halt; end; if m=n-1 then begin writeln(1); close(input); close(output); halt; end; for i:=1 to m do read(line[i].u,line[i].v,line[i].c); qsort(1,m); tot:=0; for i:=1 to m do begin x:=root(line[i].u); y:=root(line[i].v); if x<>y then begin inc(tot); dl[tot]:=line[i].c; father[x]:=y; end; if tot=n-1 then break; end; if tot<n-1 then begin writeln(0); close(input); close(output); halt; end; fillchar(father,sizeof(father),0); ans:=1; i:=1; k:=1; while i<=m do begin while line[i].c<>dl[k] do inc(i); s:=i; while (line[i].c=dl[k]) do inc(i); count:=1; while (k<tot)and(dl[k+1]=dl[k]) do begin inc(count); inc(k); end; inc(k); now:=0; can:=false; search(s,s,i-1,count); father:=cop; ans:=(ans*now) mod maxn; if k>tot then break; end; writeln(ans); close(input); close(output);end.
- 巨额奖金 Award
- BZOJ 1016 JSOI 2008 巨额奖金 最小生成树计数
- 《怪诞行为学2》读书笔记,第一章 金钱的诱惑:为什么巨额奖金带不来高业绩?
- 巨额奖金在向你招手!这款iOS应用悬赏10万美金找漏洞
- 奖金
- My Award
- AWARD BIOS
- Jolt Award
- Turing Award
- 奖金考核办法
- 发奖金
- 奖金计算
- 关于奖金
- Sicily1424. 奖金
- 求奖金
- 1004. 奖金
- 奖金提成
- 奖金提成
- web 3d引擎
- Linux修改主机名
- 谷歌有意构建Android和摩托罗拉之间的“防火墙”
- 自己动手写数据库——前言
- java学习(转载)
- 巨额奖金 Award
- Jquery 性能优化
- OpenFileDialog无法弹出的解决方法
- Tomcat源码分析(三)------ 可携带状态的线程池
- Flex3学习轨迹:让Alert对话框不可拖动
- 设计模式之装饰模式(Decorator Pattern)
- mongodb
- WCF 教程(转)
- AndroidJNI.AttachCurrentThread