小结:
1,求1到其他点的最短路,和其他点到1的最短路,只需要反边即可。
2. 最短路维护边可以加,有时乘也是更新可以最短路的。
3,spfa判负圈只需要判断一个点入队次数>n,那么必有负圈。
4.如果对最短路更新进行了限制,那么不要直接更新,打上标记之后更新。
5.最短路可以抽象为01规划,每个边可以取,可以不取。
6.传递闭包往往会很像拓扑。
7.必要时把边权压成点权,边和边之间可能也会有权。
A - Til the Cows Come Home
板题:
#include<cstdio> #include<vector> #include<queue> using namespace std; #define pb push_back typedef long long ll; const int inf=0x3f3f3f3f; const int maxn=1e3+5; int n,m; struct edge{int v,w;edge(int a,int b){v=a,w=b;}}; struct node{ int id,dis; node(int a,int b){id=a,dis=b;} friend bool operator<(node a,node b){ return a.dis>b.dis; } }; vector<edge>e[maxn]; int dis[maxn]; bool done[maxn]; void dijkstra(){ int s=1; for(int i=0;i<=n;i++)dis[i]=inf,done[i]=0; dis[s]=0; priority_queue<node>Q; Q.push(node(s,0)); while(!Q.empty()){ node u=Q.top();Q.pop(); if(done[u.id])continue; done[u.id]=1; for(int i=0;i<e[u.id].size();i++){ edge y=e[u.id][i]; if(done[y.v])continue; if(dis[y.v]>y.w+dis[u.id]){ dis[y.v]=y.w+u.dis; Q.push(node(y.v,dis[y.v])); } } } } int main(){ int t; scanf("%d %d",&t,&n); for(int i=1,u,v,w;i<=t;i++){ scanf("%d %d %d",&u,&v,&w); e[u].pb(edge(v,w)); e[v].pb(edge(u,w)); } dijkstra(); printf("%d ",dis[n]); // system("pause"); return 0; }
B - Frogger
无法优化,构建图的复杂度都是O(N*N)的,上floyd
#include<cstdio> #include<cmath> #include<algorithm> using namespace std; #define rep(i,j,k) for(int i=(int)j;i<=(int)k;i++) #define per(i,j,k) for(int i=(int)k;i>=(int)j;i--) #define pb push_back typedef double db; const int maxn=2e2+5; struct point{db x,y;}P[maxn]; db dis(point a,point b){return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));} db gp[maxn][maxn]; int main(){ int n,cas=0; while(~scanf("%d",&n),n){ for(int i=1;i<=n;i++)scanf("%lf %lf",&P[i].x,&P[i].y); // db ans=dis(P[1],P[2]); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) gp[i][j]=dis(P[i],P[j]); for(int k=1;k<=n;k++) for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) gp[i][j]=min(gp[i][j],max(gp[i][k],gp[k][j])); db ans=gp[1][2]; printf("Scenario #%d ",++cas); printf("Frog Distance = %.3lf ",ans); } // system("pause"); return 0; }
C - Heavy Transportation
就是说1到n有多条路,每一条路权值必然由最小边决定,问你那条路权值最大。
两种做法:
1.最大生成树:
将边按照由大到小排序,不断加边,如果突然加入一条边1,到n联通了,说明这个就是答案。
这样保证了路径的权值由最小值决定,而且保证了最小值最大化。因为其他连边必然比当前ans小。
1 #include<cstdio> 2 #include<vector> 3 #include<queue> 4 #include<algorithm> 5 using namespace std; 6 #define pb push_back 7 typedef long long ll; 8 const int inf=0x3f3f3f3f; 9 const int maxn=1e3+5; 10 int n,m; 11 int fa[maxn]; 12 struct edge{int u,v,w;edge(int a,int b,int x){u=a,v=b,w=x;}}; 13 vector<edge>e; 14 bool cmp(edge a,edge b){return a.w>b.w;} 15 void init(){for(int i=1;i<=maxn;i++)fa[i]=i;} 16 int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);} 17 void build(int x,int y){int dx=find(x),dy=find(y);if(dx!=dy)fa[dx]=dy;} 18 int main(){ 19 int t,cas=0; 20 scanf("%d",&t); 21 while(t--){ 22 e.clear(); 23 scanf("%d %d",&n,&m); 24 for(int i=1;i<=n;i++)fa[i]=i; 25 for(int i=1,u,v,w;i<=m;i++){ 26 scanf("%d %d %d",&u,&v,&w); 27 e.pb(edge(u,v,w)); 28 } 29 sort(e.begin(),e.end(),cmp); 30 int ans=0; 31 for(int i=0;i<e.size();i++){ 32 build(e[i].v,e[i].u); 33 if(find(1)==find(n)){ans=e[i].w;break;} 34 } 35 printf("Scenario #%d: ",++cas); 36 printf("%d ",ans); 37 } 38 // system("pause"); 39 return 0; 40 }
2.最短路维护:
dis不再表示最短路,而表示某个点到源点路径的权值。
那么必然有:dis[v]<min(dis[u],w) 的更新条件,求最大权值,初始化为0而非inf,不断更新路径上的最小边,使其最大。
1 #include<cstdio> 2 #include<vector> 3 #include<queue> 4 #include<algorithm> 5 using namespace std; 6 #define pb push_back 7 typedef long long ll; 8 const int inf=0x3f3f3f3f; 9 const int N=1e5+5; 10 struct edge{int v,w;edge(int a,int b){v=a,w=b;}}; 11 vector<edge>e[N]; 12 int n,m; 13 int dis[N]; 14 bool inq[N]; 15 void spfa(int s){ 16 for(int i=1;i<=n;i++)dis[i]=0,inq[i]=0; 17 dis[s]=inf; 18 queue<int>Q; 19 Q.push(s);inq[s]=1; 20 while(!Q.empty()){ 21 int u=Q.front();Q.pop();inq[u]=0; 22 for(int i=0;i<e[u].size();i++){ 23 int v=e[u][i].v,w=e[u][i].w; 24 if(dis[v]<min(dis[u],w)){ 25 dis[v]=min(dis[u],w); 26 if(!inq[v])Q.push(v),inq[v]=1; 27 } 28 } 29 } 30 } 31 int main(){ 32 int t,cas=0; 33 scanf("%d",&t); 34 while(t--){ 35 scanf("%d %d",&n,&m); 36 for(int i=1;i<=n;i++)e[i].clear(); 37 for(int i=1,u,v,w;i<=m;i++){ 38 scanf("%d %d %d",&u,&v,&w); 39 e[u].pb(edge(v,w)); 40 e[v].pb(edge(u,w)); 41 } 42 spfa(1); 43 printf("Scenario #%d: ",++cas); 44 printf("%d ",dis[n]); 45 } 46 // system("pause"); 47 return 0; 48 }
D - Silver Cow Party
无脑题;
#include<cstdio> #include<vector> #include<queue> #include<algorithm> using namespace std; #define pb push_back typedef long long ll; const int inf=0x3f3f3f3f; const int N=1e5+5; struct edge{int v,w;edge(int a,int b){v=a,w=b;}}; vector<edge>e[N]; int n,m; int dis[N]; bool inq[N]; void spfa(int s){ for(int i=1;i<=n;i++)dis[i]=inf,inq[i]=0; dis[s]=0; queue<int>Q; Q.push(s);inq[s]=1; while(!Q.empty()){ int u=Q.front();Q.pop();inq[u]=0; for(int i=0;i<e[u].size();i++){ int v=e[u][i].v,w=e[u][i].w; if(dis[v]>dis[u]+w){ dis[v]=dis[u]+w; if(!inq[v])Q.push(v),inq[v]=1; } } } } int a[N]; int main(){ int x; scanf("%d %d %d",&n,&m,&x); // for(int i=1;i<=n;i++)e[i].clear(); for(int i=1,u,v,w;i<=m;i++){ scanf("%d %d %d",&u,&v,&w); e[u].pb(edge(v,w)); } spfa(x); for(int i=1;i<=n;i++)a[i]=dis[i]; for(int i=1;i<=n;i++) if(i!=x)spfa(i),a[i]+=dis[x]; int ans=*max_element(a+1,a+1+n); printf("%d ",ans); // } // system("pause"); return 0; }
E - Currency Exchange
就是说n种货币,可以相互交换,问你能不能交换过程中把钱变多。
如果钱变多,说明有正圈,陷在正圈里不出来,肯定一直变多。直接判正圈。
如果说一个点入队次数大于n,说明有正圈。
注意蛋疼的精度,eps设大了不行。
1 #include<cstdio> 2 #include<iostream> 3 #include<map> 4 #include<vector> 5 #include<string> 6 #include<cstring> 7 #include<queue> 8 using namespace std; 9 #define pb push_back 10 const int inf=0x3f3f3f3f; 11 struct edge{int v;double r,c;edge(int x,double y,double z){v=x,r=y,c=z;}}; 12 const int N=1e2+5; 13 const double eps=1e-10; 14 vector<edge>e[N]; 15 int n,m,s; 16 double V; 17 bool flag; 18 bool inq[N];int cnt[N]; 19 double dis[N]; 20 void spfa(){ 21 for(int i=1;i<=n;i++)cnt[i]=0,inq[i]=0,dis[i]=0.0; 22 queue<int>Q; 23 Q.push(s);inq[s]=1;dis[s]=V; 24 while(!Q.empty()){ 25 int u=Q.front();Q.pop();inq[u]=0; 26 for(int i=0;i<e[u].size();i++){ 27 int v=e[u][i].v;double r=e[u][i].r,c=e[u][i].c; 28 double val=(dis[u]-c)*r; 29 if(dis[v]<val){ 30 dis[v]=val; 31 if(inq[v])continue; 32 Q.push(v),inq[v]=1,++cnt[v]; 33 if(cnt[v]>n){flag=1;return ;} 34 } 35 } 36 } 37 // return 0; 38 } 39 int main(){ 40 double Rab,Cab,Rba,Cba; 41 scanf("%d %d %d %lf",&n,&m,&s,&V); 42 for(int i=1,u,v;i<=m;i++){ 43 scanf("%d %d %lf %lf %lf %lf",&u,&v,&Rab,&Cab,&Rba,&Cba); 44 e[u].pb(edge(v,Rab,Cab)); 45 e[v].pb(edge(u,Rba,Cba)); 46 } 47 flag=0; 48 spfa(); 49 if(flag)puts("YES"); 50 else puts("NO"); 51 // system("pause"); 52 return 0; 53 }
F - Wormholes
直接spfa判负圈。
1 #include<cstdio> 2 #include<iostream> 3 #include<map> 4 #include<vector> 5 #include<string> 6 #include<cstring> 7 #include<queue> 8 using namespace std; 9 #define pb push_back 10 const int inf=0x3f3f3f3f; 11 const int N=6e2+5; 12 const double eps=1e-10; 13 struct edge{int v,w;edge(int a,int b){v=a,w=b;}}; 14 vector<edge>e[N]; 15 int n,m,W; 16 bool flag; 17 bool inq[N]; 18 int dis[N]; 19 int cnt[N]; 20 void spfa(){ 21 for(int i=1;i<=n;i++)inq[i]=0,cnt[i]=0,dis[i]=inf; 22 queue<int>Q; 23 Q.push(1),inq[1]=1;dis[1]=0; 24 while(!Q.empty()){ 25 int u=Q.front();Q.pop();inq[u]=0; 26 for(int i=0;i<e[u].size();i++){ 27 int v=e[u][i].v,w=e[u][i].w; 28 if(dis[v]>dis[u]+w){ 29 dis[v]=dis[u]+w; 30 if(inq[v])continue; 31 Q.push(v),inq[v]=1,++cnt[v]; 32 if(cnt[v]>n){flag=1;return ;} 33 } 34 } 35 } 36 } 37 int main(){ 38 int T;scanf("%d",&T); 39 while(T--){ 40 scanf("%d %d %d",&n,&m,&W); 41 for(int i=1;i<=n;i++)e[i].clear(); 42 for(int i=1,u,v,w;i<=m;i++){ 43 scanf("%d %d %d",&u,&v,&w); 44 e[u].pb(edge(v,w)); 45 e[v].pb(edge(u,w)); 46 } 47 for(int i=1,u,v,w;i<=W;i++){ 48 scanf("%d %d %d",&u,&v,&w); 49 e[u].pb(edge(v,-w)); 50 } 51 flag=0; 52 spfa(); 53 // cout<<"test"<<endl; 54 // for(int i=1;i<=n;i++)cout<<i<<" "<<dis[i]<<endl; 55 // cout<<"test "<<dis[1]<<endl; 56 if(flag)puts("YES"); 57 else puts("NO"); 58 } 59 // system("pause"); 60 return 0; 61 }
G - MPI Maelstrom
无脑;
#include<cstdio> #include<iostream> #include<map> #include<vector> #include<string> #include<cstring> #include<queue> #include<cstdlib> #include<algorithm> using namespace std; #define pb push_back const int inf=0x3f3f3f3f; const int N=1e2+5; int gp[N][N]; int n; void floyd(){ for(int k=1;k<=n;k++){ for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ // gp[i][j]=min(gp[i][j]) if(gp[i][j]>gp[i][k]+gp[k][j]) gp[i][j]=gp[i][k]+gp[k][j]; } } } } char s[1000]; int main(){ while(~scanf("%d",&n)){ memset(gp,0,sizeof gp); for(int i=1;i<=n;i++)gp[i][i]=0; for(int i=2;i<=n;i++){ for(int j=1;j<=i-1;j++){ scanf("%s",s); int a; if(s[0]=='x')a=inf; else a=atoi(s); gp[j][i]=gp[i][j]=a; } } floyd(); // int ans= * max_element(gp+1+n,gp+n*n); int ans=0; for(int i=1;i<=n;i++){ // for(int j=1;j<=n;j++){ if(gp[1][i]!=inf)ans=max(ans,gp[1][i]); // } } printf("%d ",ans); } // system("pause"); return 0; }
H - Cow Contest
就是说n个人之间有着相互关系,问你能有几个确定排名。
开始自然想拓扑,但不好解决。
考虑传递闭包,如果a比b牛逼,b比c牛逼,那么a比c牛逼。
如果说一个点,和其他n-1个点关系明确,那么这个点就是明确的。
#include<cstdio> #include<vector> #include<queue> #include<cstring> using namespace std; typedef long long ll; #define pb push_back const int inf=0x3f3f3f3f; const ll mod=1e9+7; const int N=1e2+6; int gp[N][N]; int n,m; void floyd(){ for(int k=1;k<=n;k++){ for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ gp[i][j]|=(gp[i][k])&(gp[k][j]); } } } } int main(){ scanf("%d %d",&n,&m); memset(gp,0,sizeof gp); for(int i=1,u,v;i<=m;i++){ scanf("%d %d",&u,&v); gp[u][v]=1; } floyd(); int ans=0; for(int i=1;i<=n;i++){ int sum=0; for(int j=1;j<=n;j++){ if(gp[i][j]||gp[j][i])sum++; } if(sum==n-1)ans++; } printf("%d ",ans); // for(int i=1;i<=n;i++)scanf("%d",&a[i]); // system("pause"); return 0; }
I - Arbitrage
套利:就是说一个货币,和其他货币不断交换后,最后变多了。问你有没有套利。
开始想dfs,感觉没啥毛病,但就是不对。
考虑最短路维护最大的交换钱,最后判断dis[1]即可。
#include<cstdio> #include<iostream> #include<map> #include<vector> #include<string> #include<cstring> using namespace std; const int N=1e2+5; #define pb push_back char s[N][N],s1[N],s2[N]; const double eps=1e-8; int n,m; double gp[N][N]; void floyd(){ for(int k=1;k<=n;k++){ for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ if(gp[i][j]<gp[i][k]*gp[k][j]) gp[i][j]=gp[i][k]*gp[k][j]; } } } } map<string,int>mp; int main(){ int cas=0; while(~scanf("%d",&n),n){ mp.clear(); for(int i=1;i<=n;i++)scanf("%s",s[i]),mp[ s[i] ]=i,gp[i][i]=1.0; memset(gp,1,sizeof gp); scanf("%d",&m); for(int i=1,u,v;i<=m;i++){ double w; scanf("%s %lf %s",s1,&w,s2); // cout<<"test :"<<s1<<" "<<s2<<endl; u=mp[s1];v=mp[s2]; gp[u][v]=w; } floyd(); // for(int i=1;i<=n;i++){ // for(int j=1;j<=n;j++){ // cout<<i<<" "<<j<<" "<<gp[i][j]<<endl; // } // } bool flag=0; for(int i=1;i<=n;i++){ if(gp[i][i]>1){flag=1;break;} } printf("Case %d: ",++cas); if(flag)puts("Yes"); else puts("No"); } // system("paus?e");// bool vis[N],flag; return 0; } // 3 // USDollar // BritishPound // FrenchFranc // 3 // USDollar 0.5 BritishPound // BritishPound 10.0 FrenchFranc // Frenc0hFranc 0.21 USDollar // 3 // USDollar // BritishPound // FrenchFranc // 6 // USDollar 0.5 BritishPound // USDollar 4.9 FrenchFranc // BritishPound 10.0 FrenchFranc // BritishPound 1.99 USDollar // FrenchFranc 0.09 BritishPound // FrenchFranc 0.19 USDollar // 0
J - Invitation Cards
题意:求1到其他点的最短路和,以及其他点到1点最短路之和,
直接无脑跑是不行的,寻求问题转化。
就是说要找其他点到1点的最短路,把边反过来更新。
1 #include<cstdio> 2 #include<iostream> 3 #include<map> 4 #include<vector> 5 #include<string> 6 #include<cstring> 7 #include<queue> 8 #include<cstdlib> 9 #include<algorithm> 10 using namespace std; 11 #define pb push_back 12 #define fi first 13 #define se second 14 typedef long long ll; 15 const int inf=0x3f3f3f3f; 16 const int N=1e6+5; 17 int n,m; 18 struct edge{int v;ll w;edge(int a,long long b){v=a;w=b;}}; 19 vector<edge>e[N]; 20 struct mp{int x,y;long long z;}; 21 vector<mp>maps; 22 ll ans; 23 long long dis[N]; 24 bool inq[N]; 25 void spfa(){ 26 for(int i=1;i<=n;i++)dis[i]=inf,inq[i]=0; 27 queue<int>Q; 28 Q.push(1),inq[1]=1,dis[1]=0; 29 while(!Q.empty()){ 30 int u=Q.front();Q.pop();inq[u]=0; 31 for(int i=0;i<e[u].size();i++){ 32 int v=e[u][i].v;long long w=e[u][i].w; 33 if(dis[v]>dis[u]+w){ 34 dis[v]=dis[u]+w; 35 if(!inq[v])Q.push(v),inq[v]=1; 36 } 37 } 38 } 39 for(int i=1;i<=n;i++)ans+=dis[i]; 40 } 41 int main(){ 42 int T;scanf("%d",&T); 43 while(T--){ 44 scanf("%d %d",&n,&m); 45 maps.clear(); 46 ans=0; 47 int u,v;ll w; 48 for(int i=1;i<=n;i++)e[i].clear(); 49 for(int i=1;i<=m;i++){ 50 mp tmp; 51 scanf("%d %d %lld",&tmp.x,&tmp.y,&tmp.z); 52 maps.pb(tmp); 53 } 54 for(int i=0;i<m;i++){ 55 int u=maps[i].x,v=maps[i].y;long long w=maps[i].z; 56 e[u].pb(edge(v,w)); 57 } 58 spfa(); 59 for(int i=1;i<=n;i++)e[i].clear(); 60 for(int i=0;i<m;i++){ 61 int u=maps[i].x,v=maps[i].y;long long w=maps[i].z; 62 e[v].pb(edge(u,w)); 63 } 64 spfa(); 65 printf("%lld ",ans); 66 } 67 // system("pause"); 68 return 0; 69 }
K:
裸的差分约束,long long 数据。
#include<cstdio> #include<iostream> #include<map> #include<vector> #include<string> #include<cstring> #include<queue> // #include<cstdlib> #include<algorithm> using namespace std; #define pb push_back #define fi first #define se second typedef long long ll; const int inf=0x3f3f3f3f; const int N=3e4+5; // int n,m; // [N]; // void spfa(){ // for(int i=1;i<=n;i++)inq[i]=0,dis[i]=inf; // queue<int>Q; // Q.push(1);inq[1]=1;dis[1]=0; // while(!Q.empty()){ // int u=Q.front();Q.pop();inq[u]=0; // for(int i=0;i<e[u].size();i++){ // int v=e[u][i].v,w=e[u][i].w; // if(dis[v]>dis[u]+w){ // dis[v]=dis[u]+w; // if(!inq[v])Q.push(v),inq[v]=1; // } // } // } // } int head[N],cnt;//cnt main里初始化为0,head main初始化为-1 struct edge{int to,w,next;}e[N*10];//注意有重边,乘10 struct node{int id,dis;//id点,dis距离 node(int x,int y){id=x,dis=y;} friend bool operator<(node a,node b){ return a.dis>b.dis;//距离小的出队 } }; void add(int u,int v,int w){//加边 e[cnt].to=v,e[cnt].w=w,e[cnt].next=head[u],head[u]=cnt++; } int dis[N]; bool done[N];//dis记录距离,done记录是否找到最短路 int n,m; void dijkstra(){ int s=1;//s起点 视情况调整 for(int i=1;i<=N;i++)dis[i]=inf,done[i]=0; dis[s]=0; priority_queue<node>Q; Q.push(node(s,0)); while(!Q.empty()){ int x=Q.top().id; Q.pop(); if(done[x])continue; done[x]=1; for(int i=head[x];i!=-1;i=e[i].next){ int y=e[i].to; if(done[y])continue; if(dis[y]>dis[x]+e[i].w)dis[y]=dis[x]+e[i].w;//更新距离 Q.push(node(y,dis[y])); } } } int main(){ memset(head,-1,sizeof head); scanf("%d %d",&n,&m); for(int i=1,u,v,w;i<=m;i++){ scanf("%d %d %d",&u,&v,&w); // e[u].pb(edge(v,w)); add(u,v,w); } dijkstra(); // int ans= * max_element(dis+1,dis+1+n); int ans=0; for(int i=1;i<=n;i++)ans=max(ans,dis[i]); printf("%d ",ans); // system("pause"); return 0; }
L:傻逼题,样例都没法测
M - 昂贵的聘礼
解法:挺简单的,就是没考虑限制,按照区间进行枚举即可,蛋疼的g++过不了。
#include<cstdio> #include<vector> #include<queue> #include<iostream> #include<cstring> using namespace std; const int N=1e2+5; typedef long long ll; const int inf=0x3f3f3f3f; #define pb push_back int n,m; int gp[N][N]; int lim[N]; int val[N],dis[N];bool inq[N],can[N]; int spfa(){ for(int i=1;i<=n;i++)inq[i]=0,dis[i]=inf; queue<int>Q; Q.push(1),inq[1]=1;dis[1]=0; while(!Q.empty()){ int u=Q.front();Q.pop();inq[u]=0; for(int i=1;i<=n;i++){ if(dis[i]>dis[u]+gp[u][i]&&can[i]){ dis[i]=dis[u]+gp[u][i]; if(!inq[i])Q.push(i),inq[i]=1; } } } int cur=inf; for(int i=1;i<=n;i++){ cur=min(cur,dis[i]+val[i]); } return cur; } int main(){ scanf("%d %d",&m,&n); for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ if(i==j)gp[i][j]=0; else gp[i][j]=inf; } } for(int i=1,q;i<=n;i++){ scanf("%d %d %d",&val[i],&lim[i],&q); for(int j=1,v;j<=q;j++){ int w; scanf("%d %d",&v,&w); // e[i].pb(edge(v,w)); gp[i][v]=w; } } int ans=inf; for(int i=0;i<=m;i++){ memset(can,0,sizeof can); for(int j=1;j<=n;j++){ if(lim[j]<=lim[1]+i&&lim[j]>=lim[1]-m+i)can[j]=1; // spfa(); ans=min(ans,spfa() ); } } printf("%lld ",ans); // system("pause"); return 0; }
R - 0 or 1
题意:给你一个矩阵C,让你求一个矩阵01矩阵X,
满足:.X 12+X 13+...X 1n=1 ,
X 1n+X 2n+...X n-1n=1
∑X ki (1<=k<=n)=∑X ij (1<=j<=n).
使得
#include<bits/stdc++.h> using namespace std; typedef long long ll; const ll MOD=1e9+7; #define pb push_back const int inf=0x3f3f3f3f; int n; const int N=3e2+5; int dis[N],C[N][N];bool inq[N]; void spfa(int s){ for(int i=1;i<=n;i++)inq[i]=0,dis[i]=inf; queue<int>Q;Q.push(s);inq[s]=1; for(int i=1;i<=n;i++){ if(i==s)dis[i]=inf; else dis[i]=C[s][i],Q.push(i); } while(!Q.empty()){ int u=Q.front();Q.pop();inq[u]=0; for(int i=1;i<=n;i++){ if(dis[i]>dis[u]+C[u][i]){ dis[i]=dis[u]+C[u][i]; if(!inq[i])Q.push(i),inq[i]=1; } } } } int main(){ while(~scanf("%d",&n)){ for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++) scanf("%d",&C[i][j]); } spfa(1); int ans=dis[n]; int d1=dis[1]; spfa(n); int d2=dis[n]; ans=min(ans,d1+d2); printf("%d ",ans); } // system("pause"); return 0; }