题目
2013北大校赛
题意:
有一片竹林,分为n个区域,每个区域有k个状态,可能互不相同,但是总的状态数只有sk个。时间每过1单位所有区域的状态都会变化,周而复始,每个区域的变化顺序都会告诉你。
区域间有m条无向边,每条边连接u和v,行走时间花费是d(e),精力花费floor(w(e)×f(p(u,i),p(v,j))),其中p(u,i)是从u出发时u的状态,p(v,j)是到达v时v的状态,f是一个给定的矩阵,矩阵值是任意两个状态间的参数,w(e)是这条边的另一个参数。
在一个区域内也可以不走,花费c(i)精力可以在区域内度过1单位的时间。
现在进入区域1,走到区域n的最少精力?
解法:
重新建图,每个区域拆成k个点,由于原边花费时间是确定的,所以从u的什么状态出发,到达的v的状态也是确定,也就是知道花费的精力,所以新边权为花费的精力。同区域的点间按顺序也连上边权为c(i)的边。
最后跑最短路就行了。
RE了一次,因为某个vi[to[i]]写成了vi[i],光荣越界T_T
Time:350ms Memory:6100kB Length:2080 B #include <iostream> #include <cstdio> #include <queue> #include <cmath> #include <cstring> #include <algorithm> #define EPS 1e-3 #define MAXN 100010 #define MAXM 4000005 #define INF 1000000007 #define MOD 1000000007 using namespace std; int he[MAXN],to[MAXM],nex[MAXM],co[MAXM],top; int yinshe[MAXN][11]; double f[30][30]; int dis[MAXN]; bool vi[MAXN]; void add(int u,int v,int w) { if(u==v) return ; to[top]=v; nex[top]=he[u]; co[top]=w; he[u]=top++; } void SPFA(int k) { queue<int> que; memset(vi,0,sizeof(vi)); memset(dis,0x3f,sizeof(dis)); dis[0]=0; que.push(0); while(que.size()) { int now=que.front(); que.pop(); vi[now]=0; for(int i=he[now];i!=-1;i=nex[i]) if(dis[to[i]]>dis[now]+co[i]) { dis[to[i]]=dis[now]+co[i]; if(!vi[to[i]]) vi[to[i]]=1,que.push(to[i]); } } } int main() { //freopen("C:\\Documents and Settings\\k99\\My Documents\\input.txt","r",stdin); int t,n,m,k,sk,ans; scanf("%d",&t); while(t--) { scanf("%d%d%d%d",&n,&m,&k,&sk); memset(he,-1,sizeof(he)); top=0; for(int i=0;i<n;++i) { int tmp; scanf("%d",&tmp); for(int j=0;j<k;++j) scanf("%d",&yinshe[i][j]),add(i*k+j,i*k+(j+1)%k,tmp); } for(int i=0;i<sk;++i) for(int j =0;j<sk;++j) scanf("%lf",&f[i][j]); for(int i=0;i<m;++i) { int u,v,w,d; scanf("%d%d%d%d",&u,&v,&w,&d); for(int j=0;j<k;++j) add((u-1)*k+j,(v-1)*k+(j+d)%k,(int)floor(w*f[yinshe[u-1][j]-1][yinshe[v-1][(j+d)%k]-1])); //cout<<(w*f[yinshe[u-1][j]-1][yinshe[v-1][(j+d)%k]-1])<<endl; } SPFA(k); ans=INF; for(int i=0;i<k;++i) ans=min(ans,dis[(n-1)*k+i]); printf("%d\n",ans); } return 0; }