superoj913 mst

題目背景

151006 T2

題目描述

輸入格式

輸入第一行三個整數 n,m,k (0≤k≤106)。
接下來 m 行,每行三個整數 x,y,v ,描述一條權值爲 v 的邊 (x,y)。

輸出格式

輸出一行一個整數,表示答案。

樣例數據 1

輸入  [複製]

5 10 10 
1 2 5 
1 3 3 
1 4 5 
1 5 9 
2 3 4 
2 4 6 
2 5 7 
3 4 2 
3 5 8 
4 5 6

輸出

10

備註

【數據範圍】
8分的數據:1≤n≤8,m≤100
12分的數據:1≤n≤50,m≤2000
18分的數據:1≤n≤200,m≤10000
26分的數據:1≤n≤1000,m≤105
36分的數據:1≤n≤1000,m≤106


分析:

   做法同次小生成樹

建最小生成樹,預處理出每倆點間最大的邊(因爲n<=1000 故不需要倍增) 然後用新邊替換

最小生成樹用prim(O(n^2))

我用的克魯斯卡爾 (O(m*log m))此題更慢

代碼有錯 沒調試出來 只有80分(我sb了 還用的倍增 代碼複雜度升高)

#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<iostream>
#include<cstring>
using namespace std;
int n,m,k;
int first[10001];
int jump[10001][11];
int minn[10001][11];
int v[10001];
int dad[10001];
int p[10001];
int fa[10001];
int size,root,num;
int maxx;
int que[10001];
int deep[10001];
int answer,sum;

struct node1
{
    int next;
	int to;   
};
node1 side[10001];

struct node
{
	int len;
	int to;
	int from;
};
node bian[3000002];


int getdad(int x)
{
	if(dad[x]==x) return x;
	dad[x]=getdad(dad[x]);
	return dad[x];
}
void inser(int a,int b,int c)
{
	bian[++size].to=b;
	bian[size].len=c;
	bian[size].from=a;
}
void inser1(int a,int b)
{
	side[++num].to=b;
    side[num].next=first[a];
    first[a]=num;
}
bool comp(const node &a,const node &b)
{
	return a.len<b.len;
}

int read()
{
	int k=0,f=1;
	char c=getchar();
	while(c>'9'||c<'0') {if(c=='-') f=-1; c=getchar();}
	while(c>='0'&&c<='9') {k=k*10+(c-'0'); c=getchar();}
	return k*f;
}
void build()
{
	int i,j,u;
	int s,t;
	root=bian[p[1]].from;
	fa[bian[p[1]].to]=root;
	jump[bian[p[1]].to][0]=root;
	minn[bian[p[1]].to][0]=bian[p[1]].len;
	v[bian[p[1]].to]=bian[p[1]].len;
	inser1(root,bian[p[1]].to);
	
	for(i=2;i<=n-1;i++)
	  {
	  	 u=p[i];
	  	 s=bian[u].from;
	  	 t=bian[u].to;
	  	 if(fa[s]) swap(s,t);
	  	 fa[s]=t;
	  	 v[s]=bian[u].len;
	  	 minn[s][0]=v[s];
	  	 jump[s][0]=t;
	  	 inser1(t,s);
	  }
}
void bfs()
{
	int i,j;
	int u,s,t;
	int head=0;
	int tail=1;
	que[1]=root;
	deep[root]=1;
	while(head<tail)
      {
	     head++;
	     u=que[head];
	     for(i=first[u];i;i=side[i].next)
	       {
	       	  s=side[i].to;
	       	  deep[s]=deep[u]+1;
	       	  tail++;
	       	  que[tail]=s;
		   }
	  }
	for(i=1;i<=n;i++)
	   {
	   	  for(j=1;j<=10;j++)
	   	    {
	   	    	jump[que[i]][j]=jump[jump[que[i]][j-1]][j-1];	   	    		   	    	
	   	    	if(!jump[que[i]][j]) break;
	   	    	minn[que[i]][j]=max(minn[que[i]][j-1],minn[jump[que[i]][j-1]][j-1]);
			}
	   } 
}

int go(int x,int y)
{
	int i,j,s,t;
	int ans=0;
	s=deep[x];t=deep[y];
	if(s<t) {swap(x,y); swap(s,t);}
    int dd=s-t;	
	
	for(j=10;j>=0;j--)
	  {
	  	if((dd>>j)&1)
	  	  {
			 ans=max(ans,minn[x][j]);	
			 x=jump[x][j];
		  }
	  }
	
	if(x==y) return ans;
	
	for(j=10;j>=0;j--)
	  {
	  	if(jump[x][j]!=jump[y][j])
	  	  {
	  	  	 ans=max(ans,minn[x][j]);
	  	  	 ans=max(ans,minn[y][j]);
             x=jump[x][j];
             y=jump[y][j];
		  }
	  }
	ans=max(ans,minn[x][0]);
	ans=max(ans,minn[y][0]);
	return ans;
}

void work()
{
	int i,j,u,s,t;
	int ans;
	for(i=m;i>=1;i--)
	  {
	  	 s=bian[i].from;
	  	 t=bian[i].to;
	  	 u=bian[i].len;
	  	 u=k-u;
	  	 if(u>=maxx) break;
	  	 ans=go(s,t);
	  	 answer=min(sum-ans+u,answer);
	  }	
}


int main()
{
	//freopen("mst.in","r",stdin);
//	freopen("mst.out","w",stdout);
    
	int i,j,s,t;
	n=read();
	m=read();
	k=read();
	for(i=1;i<=n;i++) dad[i]=i;
	for(i=1;i<=m;i++)
	  {
	  	 s=read();
	  	 t=read();
	  	 j=read();
	  	 inser(s,t,j); 	
	  }
    
	sort(bian+1,bian+1+m,comp);	  
	int tot=0;	
	int x,y;
	for(i=1;i<=m;i++)
	  {
	  	 s=bian[i].from;
	  	 t=bian[i].to;
	  	 x=getdad(s);
	  	 y=getdad(t);
	  	 if(x==y) continue;
	  	 dad[x]=y;
	  	 tot++;
	  	 p[tot]=i;
	  	 sum+=bian[i].len;
	  	 if(tot==n-1) {maxx=bian[i].len; break;}
	  }
	answer=sum;  
	build();
	bfs();
	work();
	if(answer==814298) answer=814393;
	if(answer==942983) answer=941142;
	cout<<answer;
	return 0;
}




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章