http://codeforces.com/contest/189
//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
题意:n个城市,m辆车,r场比赛。给出m辆车在n个城市中的最短路。r场比赛给出s(起点),t(终点),k(允许换乘次数)
题解:首先预处理出m辆车在n个城市中的最短路(其实我只会用dij)。d[i][j][k]表示i到j换乘了k次。
#include <algorithm>
#include <iostream>
#include <cstring>
#include <vector>
#include <cstdio>
#include <string>
#include <cmath>
#include <queue>
#include <set>
#include <map>
using namespace std;
typedef long long ll;
#define de(x) cout << #x << "=" << x << endl
int a[65][65][65],b[65][65][65],d[65][65][1005],vis[65];//s,t,k
int n,m,r;
void Dijkstra(int x,int y) {
memset(vis,0,sizeof(vis));
vis[y]=1;
for(int i=1;i<=n;++i) b[x][y][i]=a[x][y][i];
for(int i=1;i<n;++i) {
int ans=0x3f3f3f,pos;
for(int j=1;j<=n;++j) {
if(!vis[j]&&b[x][y][j]<ans) {
ans=b[x][y][j];
pos=j;
}
}
vis[pos]=1;
for(int j=1;j<=n;++j) {
if(!vis[j]&&b[x][y][pos]+a[x][pos][j]<b[x][y][j]) {
b[x][y][j]=b[x][y][pos]+a[x][pos][j];
}
}
}
}
int main() {
while(~scanf("%d%d%d",&n,&m,&r)) {
//第i辆车,j到k
for(int i=1;i<=m;++i) {
for(int j=1;j<=n;++j) {
for(int k=1;k<=n;++k) scanf("%d",&a[i][j][k]);
}
}
memset(b,0x3f3f3f,sizeof(b));
memset(d,0x3f3f3f,sizeof(d));
for(int i=1;i<=m;++i) {
for(int j=1;j<=n;++j) {
Dijkstra(i,j);//第i辆车,以j为起点
for(int k=1;k<=n;++k) {
d[j][k][0]=min(d[j][k][0],b[i][j][k]);
}
}
}
//i到j换k次
for(int k=1;k<=65;++k) {
for(int i=1;i<=n;++i) {
for(int j=1;j<=n;++j) {
for(int x=1;x<=n;++x) {
d[i][j][k]=min(d[i][j][k],d[i][x][k-1]+d[x][j][0]);
}
}
}
}
int x,y,z;
for(int i=1;i<=r;++i) {
scanf("%d%d%d",&x,&y,&z);
if(z>65) z=65;
printf("%d\n",d[x][y][z]);
}
}
return 0;
}
//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
题意:n个点,m条边,k个特殊点。起点s,终点t。有一个健忘的人要从s走到t,但是他从特殊点开始走ans个点就不走了。请问ans最小是多少。(保证起点一定是特殊点)
题解:二分答案。
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int N=100005;
int vol[N],last[N],sz,val[N],vis[N],in[N];
struct Edge {
int pre,to;
}e[4*N];
void addEdge(int u,int v) {
e[++sz].to=v;
e[sz].pre=last[u];
last[u]=sz;
}
void initE() {
sz=0;
memset(last,-1,sizeof(last));
}
int n,m,k,s,t;
bool check(int dis) {
memset(vis,0,sizeof(vis));//有没有被访问过
memset(val,0,sizeof(val));
memset(in,0,sizeof(in));//有没有在队列里
queue<int> que;
vis[s]=1;val[s]=dis;in[s]=1;
que.push(s);
while(!que.empty()) {
int u=que.front();que.pop();in[u]=0;
if(t==u) return 1;
for(int i=last[u];i!=-1;i=e[i].pre) {
int v=e[i].to;
if(t==v) return 1;
vis[v]=1;
int tt;
if(vol[v]) tt=dis;
else tt=val[u]-1;
if(tt>val[v]) {
val[v]=tt;
if(!in[v]) {
que.push(v);
in[v]=1;
}
}
}
}
return vis[t];
}
int main() {
while(~scanf("%d%d%d",&n,&m,&k)) {
memset(vol,0,sizeof(vol));
for(int i=1;i<=k;++i) {
int x;scanf("%d",&x);
vol[x]=1;
}
initE();int u,v;
for(int i=1;i<=m;++i) {
scanf("%d%d",&u,&v);
addEdge(u,v);
addEdge(v,u);
}
scanf("%d%d",&s,&t);
int l=1,r=n,ans=-1;
while(l<=r) {
int mid=l+r>>1;
if(check(mid)) {
ans=mid;
r=mid-1;
} else {
l=mid+1;
}
}
printf("%d\n",ans);
}
return 0;
}