p1355
好久没写题解了,都怪这道题!
正解好像可以写矩阵乘法,但是!
本题n看似很大,但是考虑最优解一定是跑到一个顶点后在这个边上来回跑,然后看看跑的差不多了再去终点.
这个边一定是最短边么?不一定的,反例可以随便找啦.
这算离散化么...不懂
那么n就可以缩小到T^2了.而且T<=100,每个点有两条边,点最多也就是一整个环,100个点.
这么小的图就可以随便搞了.
那么我们的任务就是处理起点到每个点i走k条边的最短路ds[i][k],终点到每个点i走k条边的最短距离de[i][k].这个处理如果用dfs的话是会超时的,但是可以用类似动态规划的东西
de[i][k]=min(de[e[j].y][k-1]+e[j].v),e[j].x=i;
这样跑一遍的复杂度是T*T,因为每次更新k的距离时T条边总会用两次,即用x更新y,用y更新x.而且图上两个点的最短路最多用T个边,否则一定重复走了某一个边.
然后我们考虑在哪个边上来回跑,这个是不能直接确定的,只好遍历一下.然后考虑用长为几的最短路,这个也不能确定,要搞双重循环.即使如此,复杂度还是优秀的T^3.
我之所以被卡这么长时间的原因完全是初始量不会设,以为自己设的足够大了,但是还是不够用.
using namespace std; int i,f,k,j,tx,ty,tv,k1,k2; int n,T,S,E,sum; struct node { int x,y; long long v; int next; }e[210]; int tot,head[110]; long long de[110][110],ds[110][110],t; int tt[1010]; long long ans; void add(int x,int y,long long v) { tot++; e[tot].x=x; e[tot].y=y; e[tot].v=v; } long long max(long long a,long long b) { return a>b?a:b; } inline int read() { int x=0,f=1; char ch=getchar(); while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();} return x*f; } int main() { n=read();T=read();S=read();E=read(); for(i=1;i<=T;i++) { tv=read();tx=read();ty=read(); tt[tx]=tt[ty]=1; add(tx,ty,tv); add(ty,tx,tv); } for(i=1;i<=1000;i++) if(tt[i]) sum++,tt[i]=sum; S=tt[S]; E=tt[E]; for(i=1;i<=tot;i++) { e[i].x=tt[e[i].x]; e[i].y=tt[e[i].y]; e[i].next=head[e[i].x]; head[e[i].x]=i; } //cout<<sum<<' '; for(i=1;i<=sum;i++) { for(k=0;k<=T;k++) ds[i][k]=de[i][k]=400000000; } ans=1000000000; ds[S][0]=0; de[E][0]=0; for(k=1;k<=T;k++) for(i=1;i<=sum;i++) for(j=head[i];j;j=e[j].next) { ds[i][k]=min(ds[i][k],ds[e[j].y][k-1]+e[j].v); de[i][k]=min(de[i][k],de[e[j].y][k-1]+e[j].v); } for(i=1;i<=tot;i++) { for(k1=0;k1<=T;k1++) for(k2=0;k2<=T;k2++) { t=n-k1-k2; if(t%2==0||t<0)continue; t=t*e[i].v; ans=min(ans,de[e[i].x][k1]+ds[e[i].y][k2]+t); ans=min(ans,de[e[i].y][k1]+ds[e[i].x][k2]+t); } } cout<<ans; }