NPSC補完計劃

登入註冊帳號.

請輸入帳號, 密碼以及預計登入時間
進階搜尋  

最新消息:

歡迎光臨NPSC補完計劃

+ NPSC補完計劃 » NPSC國中組 » NPSC2012國中組初賽
 C 胖胖天的野望

作者 主題: C 胖胖天的野望  (閱讀 1736 次)

v779n

  • 新手
  • *
  • 文章數: 3
    • 檢視個人資料
C 胖胖天的野望
« 於: 十一月 16, 2013, 11:00:03 pm »

為什麼都沒人解?
記錄

darry140

  • 初級會員
  • **
  • 文章數: 32
    • 檢視個人資料
Re: C 胖胖天的野望
« 回覆 #1 於: 一月 14, 2014, 09:59:00 pm »

這題是考最小&嚴格次小生成樹
但是我沒寫過= =
改天有空推推看 再寫
//類似題型:BZOJ 1977
-------------------------------
嗯...根本就是同一個題型啊
Google上隨便抓個Code
再改改I/O就過官測了
而且還神快= = (745ms/30000ms)
代碼: [選擇]
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<functional>
using namespace std;
#define MAXN (1000+10)
#define MAXM (30300+10)
#define Li (17)
#define INF (2000000000)
int edge[MAXM],pre[MAXM],weight[MAXM],next[MAXM],size=0;
int addedge(int u,int v,int w)
{
edge[++size]=v;
weight[size]=w;
next[size]=pre[u];
pre[u]=size;
}
int addedge2(int u,int v,int w)
{
addedge(u,v,w);
addedge(v,u,w);
}
int f[MAXN][Li]={0},dp[MAXN][Li]={0},dp0[MAXN][Li]={0},deep[MAXN],n,m;
struct E
{
int u,v,w;
friend bool operator<(E a,E b){return a.w<b.w; }
}e[MAXM];
bool b[MAXM],vis[MAXN];
int queue[MAXN],head,tail;
void bfs()
{
memset(vis,0,sizeof(vis));
head=tail=1;queue[1]=1;vis[1]=1;deep[1]=0;
while (head<=tail)
{
int &u=queue[head];
if (u!=1)
{
for (int i=1;i<17;i++)
{
if (f[u][i-1])
{
f[u][i]=f[f[u][i-1]][i-1];
}
if (f[u][i]==0) break;
if (f[u][i])
{
dp[u][i]=max(dp[u][i-1],dp[f[u][i-1]][i-1]);
}
if (i==1)
{
if (dp[u][0]!=dp[f[u][0]][0]) dp0[u][1]=min(dp[u][0],dp[f[u][0]][0]);
else dp0[u][1]=-1;
}
else
{
dp0[u][i]=max(dp0[u][i-1],dp0[f[u][i-1]][i-1]);
if (dp[u][i-1]!=dp[f[u][i-1]][i-1]) dp0[u][i]=max(dp0[u][i],min(dp[u][i-1],dp[f[u][i-1]][i-1]));
}
}
}
for (int p=pre[u];p;p=next[p])
{
int &v=edge[p];
if (!vis[v])
{
queue[++tail]=v;
vis[v]=1;deep[v]=deep[u]+1;
f[v][0]=u;dp[v][0]=weight[p];dp0[v][0]=-1;
}
}
head++;
}
}
int bin[Li];
void check(int &nowdp,int &nowdp0,int c)
{
if (c<=nowdp0) return;
else if (nowdp0<c&&c<nowdp) nowdp0=c;
else  if (c==nowdp) return;
else if (nowdp<c) {nowdp0=nowdp;nowdp=c;}
}
int lca(int x,int y,int &nowdp,int &nowdp0)
{
nowdp=nowdp0=-1;
if (deep[x]<deep[y]) swap(x,y);
int t=deep[x]-deep[y];
for (int i=0;t;i++)
if (t&bin[i])
{
check(nowdp,nowdp0,dp[x][i]);
check(nowdp,nowdp0,dp0[x][i]);
x=f[x][i];
t-=bin[i];
}
int i=Li-1;
while (x^y)
{
while (f[x][i]==f[y][i]&&i) i--;
check(nowdp,nowdp0,dp[x][i]);
check(nowdp,nowdp0,dp0[x][i]);
check(nowdp,nowdp0,dp[y][i]);
check(nowdp,nowdp0,dp0[y][i]);
x=f[x][i];y=f[y][i];
}
}
int father[MAXN];
long long sum_edge=0;
int getfather(int x){return (father[x]==x?x:father[x]=getfather(father[x]));}
void union2(int x,int y){father[father[x]]=father[father[y]];}
void init()
{
for (int i=1;i<=n;i++)
father[i]=i;
memset(b,0,sizeof(b));
memset(next,0,sizeof(next));
size=sum_edge=0;
for (int i=0;i<Li;i++)
bin[i]=1<<i;
memset(f,0,sizeof(f));
memset(dp,0,sizeof(dp));
memset(dp0,0,sizeof(dp0));
memset(deep,0,sizeof(deep));
memset(queue,0,sizeof(queue));
memset(edge,0,sizeof(edge));
memset(pre,0,sizeof(pre));
memset(weight,0,sizeof(weight));
memset(next,0,sizeof(next));
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
init();
for (int i=1;i<=m;i++)
scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w),e[i].u++,e[i].v++;
sort(e+1,e+1+m);
for (int i=1;i<=m;i++)
{
if (getfather(e[i].u)!=getfather(e[i].v)) {union2(e[i].u,e[i].v);addedge2(e[i].u,e[i].v,e[i].w);sum_edge+=e[i].w; }
else b[i]=1;
}
bfs();
for(int i=1;i<=n&&sum_edge>=0;i++)
if(getfather(i)!=getfather(1))
sum_edge=-1;
long long mindec=-1;
for (int i=1;i<=m&&sum_edge>=0;i++)
if (b[i])
{
int nowdp,nowdp0;
lca(e[i].u,e[i].v,nowdp,nowdp0);
if (nowdp==e[i].w) nowdp=nowdp0;
if (nowdp==-1) continue;
if (mindec==-1||mindec>e[i].w-nowdp) mindec=e[i].w-nowdp;
}
if(sum_edge<0)
{
cout<<"-1 -1\n";
continue;
}
if(mindec<=0)
printf("%lld -1\n",sum_edge);
else
printf("%lld %lld\n",sum_edge,mindec+sum_edge);
}
return 0;
}
« 上次編輯: 一月 17, 2014, 07:04:03 pm 由 darry140 »
記錄

WYJOIER

  • 訪客
Re: C 胖胖天的野望
« 回覆 #2 於: 四月 23, 2014, 10:58:59 am »

標準的次小生成樹!!
次小生成樹Algorithm:從最小生成樹砍一邊,重新尋找當前的最小生成樹(即次小生成樹)。
代碼: [選擇]
#include <cstdio>
#include <algorithm>
#define INF 2147483647
using namespace std;
inline int Readint()
{
char c = getchar();
while( !(c >= '0' && c <= '9') )
c = getchar();
int Number = 0;
while( (c >= '0' && c <= '9') )
Number = Number*10 + (c-'0') , c = getchar();
return Number;
}
struct Edge
{
int a , b , Cost;
bool operator < ( const Edge& Object ) const {
return Cost < Object.Cost;
}
}edges[15140+1];
int Set[1000+1] , Record[1000+1];
inline int Find(int x){return x == Set[x] ? x : (Set[x] = Find(Set[x]));}
int main()
{
int T , n , m , Answer , Answer2 , Count;
T = Readint();
while( T-- )
{
n = Readint() , m = Readint();
Answer = Count = 0, Answer2 = INF;
for( int i = 0; i < m; i++ )
edges[i].a = Readint() , edges[i].b = Readint() , edges[i].Cost = Readint();
if( m < n-1 )
{
printf("-1 -1\n");
continue;
}
sort(edges,edges+m);
//stable_sort(edges,edges+m);
for( int i = 0; i < n; i++ )Set[i] = i;
for( int i = 0; i < m; i++ )
{
int a = Find(edges[i].a) , b = Find(edges[i].b);
if( a != b )
{
Answer += edges[i].Cost;
Set[a] = Find(b);
Record[Count++] = i;
}
}
if( Answer == 0 )
{
printf("-1 -1\n");
continue;
}
for( int i = 0; i < Count; i++ )
{
int Temp = 0 , x = 0;
for( int j = 0; j < n; j++ )Set[j] = j;
for( int j = 0; j < m; j++ )
{
if( j == Record[i] )continue;
int a = Find(edges[j].a) , b = Find(edges[j].b);
if( a != b )
{
x++;
Temp += edges[j].Cost;
Set[a] = Find(b);
}
}
if( x > n-1 )Temp = INF;
if( Temp > Answer && Temp < Answer2 )
Answer2 = Temp;
}
printf("%d %d\n",Answer , ((Answer2 == INF) ? -1 : Answer2));
}
return 0;
}
記錄
+ NPSC補完計劃 » NPSC國中組 » NPSC2012國中組初賽
 C 胖胖天的野望