1>暴力出奇迹

#include<cstdio>
#include<cstdlib>
#include<algorithm>
using namespace std;
int n,lim;
const int N=303;
int head[N],tot;
int ev[N<<1],ew[N<<1],enx[N<<1];
void add(int u,int v,int w)
{ ev[++tot]=v,ew[tot]=w,enx[tot]=head[u],head[u]=tot;
ev[++tot]=u,ew[tot]=w,enx[tot]=head[v],head[v]=tot; }
int dis[N],fa[N];//从源点来的最短路
int pt,distant;//最远的那个点
void dfs(int rt)//两次dfs寻找任意一条直径
{
bool conti=false;
for(int i=head[rt];i;i=enx[i])
{
if(ev[i]==fa[rt]) continue;
conti=true;
fa[ev[i]]=rt;
dis[ev[i]]=dis[rt]+ew[i];
dfs(ev[i]);
}
if(!conti && distant<dis[rt] )
distant=dis[rt],pt=rt;
}
bool us[N];
void find_ecc(int rt,int f,int dist)
{
bool conti=false;
for(int i=head[rt];i;i=enx[i])
{
if(ev[i]==f || us[ev[i]] ) continue;
conti=true;
find_ecc(ev[i],rt,dist+ew[i]);
}
if(!conti && distant<dist )
distant=dist;
}
int main()
{
scanf("%d%d",&n,&lim);
for(int i=1;i<n;i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
add(u,v,w);
}
//先找直径,迅速定下选得链的范围
int st,ed,lenth;
dfs(1);
st=pt;
dis[st]=0,fa[st]=0,distant=0;
dfs(st);
ed=pt,lenth=distant;
//开始暴力寻找偏心距,确定答案
int ans=1<<30;
for(int i=ed;i;i=fa[i])
{
//枚举寻找这个链的起始b,终止a
int a=i,b=i;
us[a]=true;
while(fa[b] && dis[a]-dis[fa[b]]<=lim )
us[fa[b]]=true,b=fa[b];
int ans2=0;
for(int t=a;t!=fa[b];t=fa[t])
{
distant=0;
find_ecc(t,0,0);
ans2=max(ans2,distant);
}
ans=min(ans2,ans);
for(int t=a;t!=b;t=fa[t])
us[t]=false;
us[b]=false;
}
printf("%d\n",ans);
return 0;
}
2>按照题目背景写大模拟
长度感人,调试过程感人......
以后一定要静态调试......
#include<cstdio>
#include<cstdlib>
#include<algorithm>
using namespace std;
inline int read()
{
int x=0; char c=getchar();
while(c<'0' || c>'9' ) c=getchar();
while(c>='0'&&c<='9' ) x=(x<<3)+(x<<1)+c-'0',c=getchar();
return x;
}
int n,lim;
const int N=303;
int head[N],tot;
int ev[N<<1],ew[N<<1],enx[N<<1];
void add(int u,int v,int w)
{ ev[++tot]=v,ew[tot]=w,enx[tot]=head[u],head[u]=tot;
ev[++tot]=u,ew[tot]=w,enx[tot]=head[v],head[v]=tot; }
int dis[N],fa[N];//从源点来的最短路
int pt,distant;//最远的那个点
void dfs(int rt)//两次dfs寻找任意一条直径
{
for(int i=head[rt];i;i=enx[i])
{
if(ev[i]==fa[rt]) continue;
fa[ev[i]]=rt;
dis[ev[i]]=dis[rt]+ew[i];
dfs(ev[i]);
}
if(distant < dis[rt] )
distant=dis[rt],pt=rt;
}
int ecc[2][N];//0是从st出发,1是从ed出发
int nx[2][N];//0是从st出发,1是从ed出发
bool cross[2][N];
int st,ed,length;
bool get_ecc(int rt,int f,int k,int goal)
{
if(rt==goal) return true;
for(int i=head[rt];i;i=enx[i])
{
if(ev[i]==f) continue;
if(get_ecc(ev[i],rt,k,goal) )
nx[k][rt]=ev[i];
int val=ecc[k][ev[i]]+ew[i];
if(val==ecc[k][rt] )
cross[k][rt]=true;
else if(val > ecc[k][rt])
ecc[k][rt]=val,cross[k][rt]=false;
}
if(nx[k][rt]) return true;
else return false;
}
int c,l,r;
void find_c(int rt)
{
if(dis[rt]*2==length)
l=r=c=rt;
else
{
int t=dis[nx[0][rt]]<<1;
if(t<=length ) find_c(nx[0][rt]);
else
{
l=rt,r=nx[0][rt];
if(length-dis[rt]*2 < t-length ) c=rt;
else c=nx[0][rt];
}
}
}
void bfs(int res)
{
while(1 && res>0 )
{
int pre=nx[1][l],nxt=nx[0][r];
bool f1=false,f2=false;
if(pre && res>=dis[l]-dis[pre] && !cross[1][l] ) f1=true;
if(nxt && res>=dis[nxt]-dis[r] && !cross[0][r] ) f2=true;
if(!f1 && !f2 ) break;
if(f1 && !f2 )
{
if(ecc[0][r]>=ecc[1][l] ) break;
else res-=dis[l]-dis[pre],l=pre;
}
else if(!f1 && f2 )
{
if(ecc[1][l]>=ecc[0][r] ) break;
else res-=dis[nxt]-dis[r],r=nxt;
}
else //都可以选,我再比较
{
if(ecc[1][l] > ecc[0][r] ) res-=dis[l]-dis[pre],l=pre;
else if(ecc[1][l]< ecc[0][r] ) res-=dis[nxt]-dis[r],r=nxt;
else
if(res >= dis[l]-dis[pre] +dis[nxt]-dis[r] )
res-=dis[l]-dis[pre] +dis[nxt]-dis[r],l=pre,r=nxt;
else break;
}
}
}
int ans;
bool us[N];
int find_s(int rt,int f)
{
int as=0;
for(int i=head[rt];i;i=enx[i])
if(ev[i]!=f && !us[ev[i]] )
as=max(as,find_s(ev[i],rt) +ew[i]);
return as;
}
void get_max_ecc(int l,int r)
{
ans=max(dis[l],length-dis[r]);
if(l==r || nx[0][l]==r ) return ;
//ans=max(ans,max(ecc[1][l],ecc[0][r]) );
for(int t=r;t!=l;t=nx[1][t]) us[t]=true;
for(int t=nx[0][l],pre=l;t!=r;pre=t,t=nx[0][t])
if(max(ecc[0][t],ecc[1][t]) >ans )
ans=max(ans,find_s(t,pre) );
}
int main()
{
n=read(),lim=read();
for(int i=1;i<n;i++)
{
int u=read(),v=read(),w=read();
add(u,v,w);
}
//先找直径,迅速定下选得链的范围
dfs(1);
st=pt;
dis[st]=0,fa[st]=0,distant=0;
dfs(st);
ed=pt,length=distant;
//写一份正解思路
get_ecc(st,0,0,ed);
get_ecc(ed,0,1,st);
find_c(st);
if(dis[r]-dis[l]>lim) l=r=c,ans=max(ecc[1][l],ecc[0][r]);
else
{
bfs(lim-(dis[r]-dis[l]));
get_max_ecc(l,r);//这里强制不选择l,r链上的点,所以有点复杂
}
printf("%d\n",ans);
return 0;
}
