Powered by:AB_IN 局外人
还是喜欢用Kruskal。
不加注释了,板子。
#include
#define rep(i,x,y) for (int i=(x);i<=(y);i++)
using namespace std;
const int maxn=200005;
int n,m,u,v,w,ans,cnt;
int fa[maxn];
struct sa{
int u,v,w;
}e[maxn];
bool cmp(struct sa x,struct sa y){
return x.w<y.w;
}
int find(int x) {
if(fa[x] == x) return x;
return fa[x] = find(fa[x]);
}
int main()
{
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
cin>>n>>m;
rep(i,1,m) cin>>e[i].u>>e[i].v>>e[i].w;
sort(e+1,e+1+m,cmp);
rep(i,1,n) fa[i]=i;
rep(i,1,m){
if(cnt==n-1) break;
w=e[i].w; u=find(e[i].u);v=find(e[i].v);
if(u!=v){
fa[u]=v;
ans+=w;
cnt++;
}
}
cout<<ans<<endl;
return 0;
}
求最小生成树的最长边。
#include
#define rep(i,x,y) for (int i=(x);i<=(y);i++)
using namespace std;
const int maxn=200005;
int n,m,u,v,w,ans,cnt;
int fa[maxn];
struct sa{
int u,v,w;
}e[maxn];
bool cmp(struct sa x,struct sa y){
return x.w<y.w;
}
int find(int x) {
if(fa[x] == x) return x;
return fa[x] = find(fa[x]);
}
int main()
{
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
cin>>n>>m;
rep(i,1,m) cin>>e[i].u>>e[i].v>>e[i].w;
sort(e+1,e+1+m,cmp);
rep(i,1,n) fa[i]=i;
rep(i,1,m){
if(cnt==n-1) break;
w=e[i].w; u=find(e[i].u);v=find(e[i].v);
if(u!=v){
fa[u]=v;
ans=max(ans,w);
cnt++;
}
}
cout<<ans<<endl;
return 0;
}
简单说就是会有 k k k颗树。
当 c n t = = n − k cnt==n-k cnt==n−k时就满足条件了。
(一般我们是一个数,所以是 c n t = = n − 1 cnt==n-1 cnt==n−1)
#include
#define rep(i,x,y) for (int i=(x);i<=(y);i++)
using namespace std;
const int maxn=200005;
int n,m,u,v,w,ans,cnt,k;
int fa[maxn];
struct sa{
int u,v,w;
}e[maxn];
bool cmp(struct sa x,struct sa y){
return x.w<y.w;
}
int find(int x) {
if(fa[x] == x) return x;
return fa[x] = find(fa[x]);
}
int main()
{
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
cin>>n>>m>>k;
rep(i,1,m) cin>>e[i].u>>e[i].v>>e[i].w;
sort(e+1,e+1+m,cmp);
rep(i,1,n) fa[i]=i;
rep(i,1,m){
if(cnt==n-k) {cout<<ans<<endl;return 0;}
w=e[i].w; u=find(e[i].u);v=find(e[i].v);
if(u!=v){
fa[u]=v;
ans+=w;
cnt++;
}
}
cout<<"No Answer"<<endl;
return 0;
}
先正常求最小生成树。
用题目给的所有边的权值 减去 最小生成树的权值即可。
#include
#define rep(i,x,y) for (int i=(x);i<=(y);i++)
using namespace std;
const int maxn=200005;
int n,m,u,v,w,ans,cnt,sum;
int fa[maxn];
struct sa{
int u,v,w;
}e[maxn];
bool cmp(struct sa x,struct sa y){
return x.w<y.w;
}
int find(int x) {
if(fa[x] == x) return x;
return fa[x] = find(fa[x]);
}
int main()
{
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
cin>>n>>m;
rep(i,1,m) cin>>e[i].u>>e[i].v>>e[i].w,sum+=e[i].w;
sort(e+1,e+1+m,cmp);
rep(i,1,n) fa[i]=i;
rep(i,1,m){
if(cnt==n-1) break;
w=e[i].w; u=find(e[i].u);v=find(e[i].v);
if(u!=v){
fa[u]=v;
ans+=w;
cnt++;
}
}
cout<<sum-ans<<endl;
return 0;
}
加注释的板子。
#include
#define rep(i,x,y) for (int i=(x);i<=(y);i++)
using namespace std;
const int maxn=200005;
int n,m,u,v,cnt;
float w,ans;
int fa[maxn];
struct sa{
int u,v;
float w;//权值
}e[maxn];
bool cmp(struct sa x,struct sa y){
return x.w<y.w;
}
int find(int x) {
if(fa[x] == x) return x;
return fa[x] = find(fa[x]);
}
int main()
{
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
while(cin>>n&&n){
ans=0.0;cnt=0;
m=n*(n-1)/2;
rep(i,1,m) cin>>e[i].u>>e[i].v>>e[i].w;
sort(e+1,e+1+m,cmp);//按权值排序
rep(i,1,n) fa[i]=i;
rep(i,1,m){
if(cnt==n-1) break;//如果边数为(顶点数-1),所有边就都弄完了,而且满足树的定义。
w=e[i].w; u=find(e[i].u);v=find(e[i].v);
if(u!=v){//如果祖先不同,则归为相同
fa[u]=v;
ans+=w;
cnt++;//边数加一。
}
}
printf("%.2f\n",ans);
}
return 0;
}
先是cmp函数:先用 j u d g e judge judge排,再用 w w w排,都是大的排在后面。
然后用 c o u n t e r counter counter记录有多少个 j u d g e = 1 judge=1 judge=1的,把他们先并起来。
再以这些边为基准生成最小生成树,当 c n t = = n − 1 − c o u n t e r cnt==n-1-counter cnt==n−1−counter时跳出。
#include
#define rep(i,x,y) for (int i=(x);i<=(y);i++)
using namespace std;
const int maxn=200;
int n,counter,u,v,w,ans,cnt;
int fa[maxn];
struct sa{
int u,v,w,judge;
}e[maxn];
bool cmp(struct sa x,struct sa y){
if(x.judge!=y.judge) return x.judge<y.judge;
else return x.w<y.w;
}
int find(int x) {
if(fa[x] == x) return x;
return fa[x] = find(fa[x]);
}
int main()
{
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
while(cin>>n){
counter=0;cnt=0;ans=0;
rep(i,1,n) fa[i]=i;
rep(i,1,n*(n-1)/2)
{
cin>>e[i].u>>e[i].v>>e[i].w>>e[i].judge;
u=find(e[i].u);v=find(e[i].v);
if(e[i].judge && u!=v)
{fa[find(u)]=find(v);counter++;}
}
sort(e+1,e+1+(n*(n-1)/2),cmp);
rep(i,1,(n*(n-1)/2)-counter){
if(cnt==n-1-counter) break;
w=e[i].w; u=find(e[i].u);v=find(e[i].v);
if(u!=v){
fa[u]=v;
ans+=w;
cnt++;
}
}
cout<<ans<<endl;
}
return 0;
}
板子。
#include
#define rep(i,x,y) for (int i=(x);i<=(y);i++)
using namespace std;
const int maxn=200005;
int n,m,u,v,cnt;
int w,ans;
int fa[maxn];
struct sa{
int u,v,w;
}e[maxn];
bool cmp(struct sa x,struct sa y){
return x.w<y.w;
}
int find(int x) {
if(fa[x] == x) return x;
return fa[x] = find(fa[x]);
}
int main()
{
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
while(cin>>n>>m&&n){
ans=0;cnt=0;
rep(i,1,n) cin>>e[i].u>>e[i].v>>e[i].w;
sort(e+1,e+1+n,cmp);
rep(i,1,m) fa[i]=i;
rep(i,1,n){
if(cnt==m-1) break;
w=e[i].w; u=find(e[i].u);v=find(e[i].v);
if(u!=v){
fa[u]=v;
ans+=w;
cnt++;
}
}
if(cnt==m-1) cout<<ans<<endl;
else cout<<"?"<<endl;
}
return 0;
}
首先得先明白路径上权值最大的一条边权值最小这句话什么意思。
就是 s − > t s->t s−>t有很多路径,每个路径都用一个边权值的最大值。
我们现在需要求的是这些最大值里面的最小值。
其实就是生成最小生成树。
因为边权值就从小到大排的。
当s和t在同一个集合时,最后那个边的权值便是答案。
#include
#define rep(i,x,y) for (int i=(x);i<=(y);i++)
using namespace std;
const int maxn=200005;
int n,m,u,v,x,y;
int k,w;
int fa[maxn];
struct sa{
int u,v,w;
}e[maxn];
bool cmp(struct sa x,struct sa y){
return x.w<y.w;
}
int find(int x) {
if(fa[x] == x) return x;
return fa[x] = find(fa[x]);
}
int main()
{
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
while(cin>>n>>m>>k){
rep(i,1,m) cin>>e[i].u>>e[i].v>>e[i].w;
sort(e+1,e+1+m,cmp);
while(k--){
int flag=0;
long long ans=0;
cin>>x>>y;
rep(i,1,n) fa[i]=i;
rep(i,1,m){
w=e[i].w; u=find(e[i].u);v=find(e[i].v);
if(u!=v){
fa[u]=v;
}
if(find(x)==find(y))
{
flag=1;
ans=e[i].w;
break;
}
}
flag==1?printf("%lld\n",ans):printf("-1\n");
}
}
return 0;
}
没用按秩合并,直接是快读。302ms过的。
#include
#define rep(i,x,y) for (int i=(x);i<=(y);i++)
typedef long long ll;
using namespace std;
const ll maxn=2e6+10;
int n,m,u,v,cnt,w;
ll ans;
int fa[maxn];
namespace IO{
char ibuf[1<<21],*ip=ibuf,*ip_=ibuf;
char obuf[1<<21],*op=obuf,*op_=obuf+(1<<21);
inline char gc(){
if(ip!=ip_)return *ip++;
ip=ibuf;ip_=ip+fread(ibuf,1,1<<21,stdin);
return ip==ip_?EOF:*ip++;
}
inline void pc(char c){
if(op==op_)fwrite(obuf,1,1<<21,stdout),op=obuf;
*op++=c;
}
inline int read(){
register int x=0,ch=gc(),w=1;
for(;ch<'0'||ch>'9';ch=gc())if(ch=='-')w=-1;
for(;ch>='0'&&ch<='9';ch=gc())x=x*10+ch-48;
return w*x;
}
template<class I>
inline void write(I x){
if(x<0)pc('-'),x=-x;
if(x>9)write(x/10);pc(x%10+'0');
}
class flusher_{
public:
~flusher_(){if(op!=obuf)fwrite(obuf,1,op-obuf,stdout);}
}IO_flusher;
}
using namespace IO;
struct sa{
int u,v,w;
}e[maxn];
bool cmp(struct sa x,struct sa y){
return x.w<y.w;
}
int find(int x) {
if(fa[x] == x) return x;
return fa[x] = find(fa[x]);
}
int main()
{
while(scanf("%d%d",&n,&m)!=-1){
ans=0;cnt=0;
rep(i,1,m) {e[i].u=read();e[i].v=read();e[i].w=read();}
sort(e+1,e+1+m,cmp);
rep(i,1,n) fa[i]=i;
rep(i,1,m){
if(cnt==n-1) break;
w=e[i].w; u=find(e[i].u);v=find(e[i].v);
if(u!=v){
fa[u]=v;
ans+=w;
cnt++;
}
}
cnt==n-1?printf("%lld\n",ans):printf("-1\n");
}
return 0;
}
这是按秩合并的函数
void join(int a,int b)
{
int a1=find(a),b1=find(b);
if(rk[a1]>rk[b1])swap(a1,b1);
fa[a1]=b1;
if(rk[a1]==rk[b1])rk[b1]++;
}
void init()
{
for(int i=1;i<=n;i++)
{fa[i]=i;rk[i]=0;}
}
可能会多个树,要排除这种情况。
#include
using namespace std;
int a,b,cnt,flag,fa[100001],vis[100001];
int find(int x)
{
if(x!=fa[x])fa[x]=find(fa[x]);
return fa[x];
}
void join(int a,int b)
{
int a1=find(a),b1=find(b);
if(a1!=b1){fa[a1]=b1;flag=0;}
else flag=1;//又连一遍就成环了
}
int main()
{
ios::sync_with_stdio(false);
while(cin>>a>>b&&!(a==-1&&b==-1))
{
if(a==0&&b==0){printf("Yes\n");continue;}//a,b都是0,也得输出yes
memset(vis,0,sizeof(vis));
for(int i=1;i<=100001;i++) fa[i]=i;
cnt=flag=0;
while(!(a==0&&b==0))
{
vis[a]=vis[b]=1;
if(!flag)join(a,b);
cin>>a>>b;
}
if(flag) {printf("No\n");continue;}
for(int i=1;i<=100001;i++)
if(vis[i]&&fa[i]==i) cnt++;
cnt==1?printf("Yes\n"):printf("No\n");
}
return 0;
}
重点就是字母顺序装换成数字
n u m b e r = u p p e r c a s e l e t t e r s − ′ A ′ + 1 number=upper\ case\ letters-'A'+1 number=upper case letters−′A′+1
n u m b e r = l o w e r c a s e l e t t e r s − ′ a ′ + 1 number=lower\ case\ letters-'a'+1 number=lower case letters−′a′+1
通用的是
n u m b e r = l e t t e r s & 31 number=letters \ \&\ 31 number=letters & 31
#include
#define rep(i,x,y) for (int i=(x);i<=(y);i++)
using namespace std;
const int maxn=200;
int n,m,w,ans,cnt,u,v;
char a,b;
int fa[maxn];
struct sa{
int u,v;
int w;
}e[maxn];
bool cmp(struct sa x,struct sa y){
return x.w<y.w;
}
int find(int x) {
if(fa[x] == x) return x;
return fa[x] = find(fa[x]);
}
int main()
{
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
while(cin>>n>>m){
cnt=0;ans=0;
rep(i,1,m) {cin>>a>>b; e[i].u=a-'A'+1; e[i].v=b-'A'+1; cin>>e[i].w;}
sort(e+1,e+1+m,cmp);
rep(i,1,n) fa[i]=i;
rep(i,1,m){
if(cnt==n-1) break;
w=e[i].w; u=find(e[i].u);v=find(e[i].v);
if(u!=v){
fa[u]=v;
ans+=w;
cnt++;
}
}
if(cnt==n-1) cout<<ans<<endl;
else cout<<"-1"<<endl;
}
return 0;
}
完结。