文章目录
- Rikka with Minimum Spanning Trees Gym - 102012A
- Networking POJ - 1287
- 最短路径·一 HihoCoder - 1081
- 最短路径·二:Floyd算法 HihoCoder - 1089
- 最短路径·三:SPFA算法 HihoCoder - 1093
- 最小生成树一·Prim算法 HihoCoder - 1097
- 最小生成树二·Kruscal算法 HihoCoder - 1098
- Heavy Transportation POJ - 1797
- 还是畅通工程 HDU - 1233
- 畅通工程再续 HDU - 1875
- 地铁 CSU - 1808
- Wormholes POJ - 3259
- 飞行路线 HYSBZ - 2763
Rikka with Minimum Spanning Trees Gym - 102012A
这道题是去年徐州区域赛的"签到题",也是我印象很深刻的打铁场。最小生成树计数,但是!!! 数据随机,其实就有很大概率不连通,或者只有一个最小生成树,所以就莽一发,拼人品,赌它只有一个最小生成树,那么把权值和输出就行了。(是不是很坑?是不是很坑!!)(之所以放在第一道,因为现场赛时也是A题,而且好多人都莽过去了…)
#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <functional>
#include <algorithm>
#include <queue>
#include <stdio.h>
#define INF 0x7f7f7f7f
#define ull unsigned long long
using namespace std;
const int maxn = 100020;
const int MOD = 1e9+7;
ull k1,k2;
int n,m;
int fa[maxn];
void init(int n)
{
for(int i = 0;i<=n;i++)fa[i] = i;
}
int find(int x)
{
return (fa[x] == x)?x : fa[x] = find(fa[x]);
}
struct Edge{
int u,v;
ull w;
}edge[maxn];
unsigned long long xors()
{
ull k3=k1,k4=k2;
k1=k4;
k3^=k3<<23;
k2=k3^k4^(k3>>17)^(k4>>26);
return k2+k4;
}
void gen()
{
//scanf("%d%d%llu%llu" , &n,&m,&k1,&k2);
scanf("%d%d%llu%llu",&n,&m,&k1,&k2);
//cin >> n >> m >>k1 >>k2;
for(int i = 1;i<=m;i++)
{
edge[i].u = xors() % n + 1;
edge[i].v = xors() % n + 1;
edge[i].w = xors();
}
}
bool cmp(Edge a,Edge b)
{
return a.w < b.w;
}
int main()
{
int T;scanf("%d",&T);
while(T--)
{
gen();
init(n);
int ct = 0;
ull sum = 0;
sort(edge+1,edge+1+m,cmp);
for(int i = 1;i<=m;i++)
{
int fx = find(edge[i].u);
int fy = find(edge[i].v);
if(fx != fy){
ct ++;
fa[fx] = fy;
sum = (sum + edge[i].w)%MOD;
}
}
if(ct != n-1)printf("0\n");
else printf("%llu\n" , sum);
}
}
Networking POJ - 1287
一个简单的最小生成树的题
#include <iostream>
#include <stdio.h>
#include <algorithm>
using namespace std;
const int maxn = 10020;
int fa[maxn];
int ct = 0;
int ans;
struct Edge{
int u,v,w;
}edge[maxn];
void init(int n)
{
ct = 0;
ans = 0;
for(int i = 0;i<=n;i++)
{
fa[i] = i;
}
}
void addedge(int u,int v,int w)
{
edge[ct].u = u;
edge[ct].v = v;
edge[ct].w = w;
ct ++;
}
bool cmp(Edge a,Edge b)
{
return a.w<b.w;
}
int find(int x)
{
return (fa[x] == x)?fa[x]:fa[x] = find(fa[x]);
}
int n,m;
int main()
{
while(cin >> n && n){
init(n);
cin >> m;
for(int i = 0;i<m;i++){
int u,v,w;
cin >> u >> v >> w;
addedge(u,v,w);
}
sort(edge,edge+ct,cmp);
for(int i = 0;i<ct;i++)
{
int u = edge[i].u , v = edge[i].v;
int fx = find(u) , fy = find(v);
if(fx != fy){
fa[fx] = fy;
ans += edge[i].w;
}
}
cout << ans << endl;
}
}
最短路径·一 HihoCoder - 1081
最短路裸题,我用dijk写的
#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <functional>
#include <algorithm>
#include <queue>
#define INF 0x7f7f7f7f
using namespace std;
const int maxn = 10020;
int ct = 0;
int ans;
int n,m,s,t;
int head[maxn];
int dis[maxn];
struct {
int v , w , next;
}edge[2*maxn];
struct node{
int x;
int dis;
bool operator < (const node b)const{
return dis > b.dis;
}
};
void init(int n)
{
for(int i = 0;i<=n;i++)head[i] = -1 ,dis[i] = INF ;
ct = 0;
}
void addedge(int u,int v,int w)
{
edge[ct].v = v;
edge[ct].w = w;
edge[ct].next = head[u];
head[u] = ct++;
}
void dijk(int now)
{
node st;
st.x = now;
st.dis = 0;
dis[now] = 0;
priority_queue<node>Q;
Q.push(st);
while(!Q.empty())
{
node t = Q.top();
Q.pop();
if(dis[t.x] != t.dis)continue;
for(int i = head[t.x];~i;i = edge[i].next)
{
int to = edge[i].v;
if(dis[t.x] + edge[i].w < dis[to]){
dis[to] = dis[t.x] + edge[i].w;
//cout << "to = " << to << " , dis[to] = " <<dis[to] << endl;
Q.push((node){to , dis[to]});
}
}
}
}
int main()
{
int T;
//cin >> T;
//for(int tt = 1;tt<=T;tt++)
// {
cin >> n >> m >> s >>t;
init(n);
for(int i = 0;i<m;i++)
{
int u,v,w;cin >> u >> v >>w;
addedge(u,v,w);
addedge(v,u,w);
//cout << "fuck" <<endl;
}
dijk(s);
cout << dis[t] << endl;
// }
}
最短路径·二:Floyd算法 HihoCoder - 1089
裸题,希望可以自己实现,非常好记
#include<iostream>
#include<string.h>
#include<stdio.h>
#include<algorithm>
#include<vector>
#include<queue>
#define clr(x,b) memset(x,(b),sizeof(x))
#define fuck cout<<"fuck:"<<__LINE__<<____endl
#define MOD (ll)(1e9+7)
using namespace std;
const int maxn = 120;
const int maxm = 1020;
int _mp[maxn][maxn];
int n,m;
int main()
{
cin>>n>>m;
clr(_mp,0x3f3f3f3f);
for(int i = 0;i<=n;i++)_mp[i][i] = 0;
for(int i = 0;i<m;i++){
int u,v,l;cin>>u>>v>>l;
if(_mp[u][v]>l){
_mp[u][v] = l;
_mp[v][u] = l;
}
}
for(int k = 1;k<=n;k++){
for(int i = 1;i<=n;i++){
for(int j = 1;j<=n;j++){
_mp[i][j] = min(_mp[i][j],_mp[i][k]+_mp[k][j]);
}
}
}
for(int i = 1;i<=n;i++){
for(int j = 1;j<=n;j++){
cout<<_mp[i][j]<<" ";
}
cout<<endl;
}
}
最短路径·三:SPFA算法 HihoCoder - 1093
也可以用别的方法,这里我是为了练习spfa,所以用的spfa
#include<iostream>
#include<algorithm>
#include<string.h>
#include<string>
#include<queue>
#include<vector>
#define clr(x,b) memset(x,(b),sizeof(x))
#define fuck cout<<"fuck:"<<__LINE__<<endl;
using namespace std;
const int maxn = 1e5+21;
const int maxm = 1e6+20;
int S,T,n,m;
int ct = 0;
int dis[maxn];
bool inq[maxn];
int num[maxn];
int head[maxn];
struct edge{
int to;
int len;
int next;
}E[maxm];
struct node{
int x;
int dis;
bool operator < (const node b)const{
return dis<b.dis;
}
};
void addedge(int u,int v,int w){
E[ct].to = v;
E[ct].len = w;
E[ct].next = head[u];
head[u] = ct++;
}
void spfa(){
queue<int>Q;
Q.push(S);
inq[S] = true;
dis[S] = 0;
num[S]++;
while(!Q.empty()){
int t = Q.front();
Q.pop();
inq[t] = false;
for(int i = head[t];i!=-1;i = E[i].next){
int x = E[i].to;
int l = E[i].len;
if(dis[x]>dis[t]+l){
dis[x] = dis[t]+l;
if(!inq[x]){
inq[x] = true;
Q.push(x);
num[x] ++ ;
if(num[x]>n)return;
}
}
}
}
}
int main(){
ct = 0;
clr(head,-1);
clr(inq,0);
clr(dis,0x3f3f3f3f);
clr(num,0);
cin>>n>>m>>S>>T;
for(int i = 0;i<m;i++){
int u,v,l;cin>>u>>v>>l;
addedge(u,v,l);
addedge(v,u,l);
}
spfa();
//fuck
cout<<dis[T]<<endl;
}
最小生成树一·Prim算法 HihoCoder - 1097
#include<iostream>
#include<algorithm>
#include<string.h>
#include<string>
#include<queue>
#include<vector>
#define clr(x,b) memset(x,(b),sizeof(x))
#define fuck cout<<"fuck:"<<__LINE__<<endl;
#define INF 0x3f3f3f3f
using namespace std;
const int maxn = 1020;
bool visit[maxn];
int dis[maxn];
int G[maxn][maxn];
int ans = 0;
int n;
void prim(){
dis[1] = 0;
for(int i = 0;i<n;i++){
int mn = INF;
int pos = 0;
for(int j = 1;j<=n;j++){
if(visit[j])continue;
if(dis[j]<mn){
mn = dis[j];
pos = j;
}
}
if(pos == 0)break;
visit[pos] = true;
ans += dis[pos];
//dis[pos] = 0;
for(int j = 1;j<=n;j++){
dis[j] = min(dis[j],G[pos][j]);
}
}
}
int main(){
clr(dis,INF);
cin>>n;
for(int i = 1;i<=n;i++){
for(int j = 1;j<=n;j++){
int a;cin>>a;
G[i][j] = a;
}
}
prim();
//fuck
cout<<ans<<endl;
}
最小生成树二·Kruscal算法 HihoCoder - 1098
#include<iostream>
#include<algorithm>
#include<string.h>
#include<string>
#include<queue>
#include<vector>
#define clr(x,b) memset(x,(b),sizeof(x))
#define fuck cout<<"fuck:"<<__LINE__<<endl;
using namespace std;
const int maxm = 1e6+20;
const int maxn = 1e5+20;
struct edge{
int u;
int v;
int len;
}E[maxm];
bool cmp(edge a,edge b){
return a.len<b.len;
}
bool visit[maxm];
int fa[maxn];
int n,m;
void init(){
for(int i = 0;i<=n;i++)fa[i] = i;
}
int find(int x){
return (fa[x] == x)?x:fa[x] = find(fa[x]);
}
void join(int a,int b){
int x = find(a);
int y = find(b);
if(x!=y)fa[x] = y;
}
int main()
{
cin>>n>>m;
clr(visit,0);
init();
for(int i = 0;i<m;i++){
cin>>E[i].u>>E[i].v>>E[i].len;
}
sort(E,E+m,cmp);
int ans = 0;
for(int i = 0;i<m;i++){
int u = E[i].u;
int v = E[i].v;
int l = E[i].len;
int x = find(u);
int y = find(v);
if(x!=y){
fa[x] = y;
ans += l;
}
else continue;
}
cout<<ans<<endl;
}
Heavy Transportation POJ - 1797
从1到n的所有路径中,输出最小值最大的路径的最小值,dijk变一下,用dis维护到当前点的最小值,每次更新时dis[x] = max(dis[t] , min(edte[i].w,dis[t.x]));
,记得优先队列中弹出的点事是离源点路径中最小值最大的点
#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <functional>
#include <algorithm>
#include <queue>
#include <stdio.h>
#define INF 0x7f7f7f7f
using namespace std;
const int maxn = 20020;
const int maxm = 1000020;
int ct = 0;
int ans;
int n,m,s,t;
int head[maxn];
int dis[maxn];
struct {
int v , w , next;
}edge[2*maxm];
struct node{
int x;
int dis;
bool operator < (const node b)const{
return dis < b.dis;
}
};
void init(int n)
{
for(int i = 0;i<=n;i++)head[i] = -1 ,dis[i] = 0 ;
ct = 0;
}
void addedge(int u,int v,int w)
{
edge[ct].v = v;
edge[ct].w = w;
edge[ct].next = head[u];
head[u] = ct++;
}
void dijk(int now)
{
node st;
st.x = now;
st.dis = INF;
dis[now] = INF;
priority_queue<node>Q;
Q.push(st);
while(!Q.empty())
{
node t = Q.top();
Q.pop();
// cout << t.x << endl;
if(dis[t.x] > t.dis)continue;
for(int i = head[t.x];~i;i = edge[i].next)
{
int to = edge[i].v;
if(min(dis[t.x] , edge[i].w) > dis[to]){
dis[to] = min(dis[t.x] , edge[i].w);
//cout << "to = " << to << " , dis[to] = " <<dis[to] << endl;
Q.push((node){to , dis[to]});
}
}
}
}
int main()
{
int T;
scanf("%d" , &T);
for(int tt = 1;tt<=T;tt++)
{
//cin >> n >> m ;
scanf("%d%d" , &n , &m);
init(n);
for(int i = 0;i<m;i++)
{
int u,v,w;//cin >> u >> v >>w;
scanf("%d%d%d",&u,&v,&w);
addedge(u,v,w);
addedge(v,u,w);
//cout << "fuck" <<endl;
}
dijk(1);
printf("Scenario #%d:\n%d\n\n",tt,dis[n]);
//cout << dis[n] << endl;
}
}
还是畅通工程 HDU - 1233
一个简单的最小生成树题
#include<iostream>
#include <algorithm>
using namespace std;
int n,ans;
int f[120];
typedef struct _fff
{
int from,to,dis;
}FFF;
FFF edge[5020];
bool cmp(FFF a,FFF b)
{
return a.dis < b.dis;
}
int find(int x)
{
if(x!=f[x])f[x] = find(f[x]);
return f[x];
}
void Union(int a,int b,int i)
{
int x = find(a);
int y = find(b);
if(x == y)return;
ans += edge[i].dis;
f[y] = x;
}
int main()
{
cin>>n;
while(n)
{
ans = 0;
for(int i=1;i<=n;i++)f[i] = i;
int k =n*(n-1)/2;
for(int i=0;i<k;i++)
{
cin>>edge[i].from>>edge[i].to>>edge[i].dis;
}
sort(edge,edge+k,cmp);
for(int i = 0;i<k;i++)
{
Union(edge[i].from,edge[i].to,i);
}
cout<<ans<<endl;
cin>>n;
}
}
畅通工程再续 HDU - 1875
在最小生成树的基础上加了一下距离限制,多个if条件即可
# include <iostream>
# include <stdio.h>
# include <string.h>
# include <algorithm>
# include <math.h>
# include <queue>
# include <string>
# include <vector>
# include <set>
# include <map>
# define INF 0x3f3f3f3f
# define clr0(x) memset(x,0,sizeof(x))
# define clr1(x) memset(x,INF,sizeof(x))
# define clrf(x) memset(x,-1,sizeof(x))
# define rep(i,a) for(int i = 0;i<(a);i++)
# define repf(i,a,b) for(int i = (a);i<=(b);i++)
# define repu(i,a,b) for(int i = (a);i<(b);i++)
# define repd(i,a,b) for(int i = (a);i>=(b);i--)
# define lowbit x&(-x)
# define ww(a) while(a)
# define sc(x) scanf("%d",&(x))
# define sd(x) scanf("%I64d",&(x))
# define lson(x) (x)<<1
# define rson(x) (x)<<1|1
# define ll long long
# define fuckio ios::sync_with_stdio(false);
# define fuck cout<<"fuck:"<<__LINE__<<endl;
# define gcd(a,b) __gcd((a),(b))
# define maxn 120
using namespace std;
int fa[maxn];
int xx[maxn];
int yy[maxn];
int n,m,cnt,num;
void init()
{
repf(i,0,n)fa[i] = i;
cnt = 0;
num = 0;
}
int find(int x)
{
return (fa[x] == x)?x:fa[x] = find(fa[x]);
}
struct edge
{
int u;
int v;
double len;
}E[maxn*maxn];
bool cmp(edge a,edge b)
{
return a.len<b.len;
}
double kruskal()
{
double ret = 0;
rep(i,cnt){
int fu = find(E[i].u);
int fv = find(E[i].v);
if(fu!=fv){
fa[fu] = fv;
ret += E[i].len;
num ++;
}
}
return ret;
}
int main()
{
int T;sc(T);
ww(T--){
sc(n);
init();
repf(i,1,n){
scanf("%d%d",&xx[i],&yy[i]);
}
repf(i,1,n){
repf(j,1,n){
double tmp =sqrt((xx[i]-xx[j])*(xx[i]-xx[j])+(yy[i]-yy[j])*(yy[i]-yy[j]));
if(tmp>=10&&tmp<=1000){
E[cnt].u = i;
E[cnt].v = j;
E[cnt++].len = tmp;
}
}
}
sort(E,E+cnt,cmp);
double ans = kruskal()*100;
if(num!=n-1)printf("oh!\n");
else printf("%.1lf\n",ans);
}
}
地铁 CSU - 1808
每个点是地铁站,每个边表示属于几号线,现在有个代价是,如果路线中相邻的两个边属于的号线不一样,就需要有额外的
∣
c
i
−
c
j
∣
|c_{i} - c_{j}|
∣ci−cj∣的换乘代价,问你从1号点到n号店的最小代价。我们这里需要加一个stt[maxn]
数组又来记录,从原点到当前点,最后一次的乘车时几号线,然后维护最小值dis[to] = min(dis[to],edge[i].w + dis[t.x] + abs(stt[t.x] - edge[i].sta));
。因为源点出发的时候,没有换乘,所以单独考虑。
#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <functional>
#include <algorithm>
#include <queue>
#include <stdio.h>
#define INF 0x7f7f7f7f
using namespace std;
const int maxn = 200020;
const int maxm = 200020;
int ct = 0;
int ans;
int n,m,s,t;
int head[maxn];
int dis[maxn];
int stt[maxn];
struct {
int v , w ,next , sta;
}edge[2*maxm];
struct node{
int x;
int dis;
bool operator < (const node b)const{
return dis > b.dis;
}
};
void init(int n)
{
for(int i = 0;i<=n;i++)head[i] = -1 ,dis[i] = INF ,stt[i] = 0;;
ct = 0;
}
void addedge(int u,int v,int w,int sta)
{
edge[ct].v = v;
edge[ct].w = w;
edge[ct].next = head[u];
edge[ct].sta = sta;
head[u] = ct++;
}
void dijk(int now)
{
node st;
st.x = now;
st.dis = 0;
stt[now] = INF;
dis[now] = 0;
priority_queue<node>Q;
Q.push(st);
while(!Q.empty())
{
node t = Q.top();
Q.pop();
// cout << t.x << endl;
if(dis[t.x] < t.dis)continue;
for(int i = head[t.x];~i;i = edge[i].next)
{
int to = edge[i].v;
if(stt[t.x] == INF && edge[i].w + dis[t.x] < dis[to]){
dis[to] = edge[i].w + dis[t.x] ;
stt[to] = edge[i].sta;
//cout << "to = " << to << " , dis[to] = " <<dis[to] << endl;
Q.push((node){to , dis[to]});
}else if(edge[i].w + dis[t.x] + abs(stt[t.x] - edge[i].sta) < dis[to]){
dis[to] = edge[i].w + dis[t.x] + abs(stt[t.x] - edge[i].sta);
stt[to] = edge[i].sta;
Q.push((node){to , dis[to]});
}
}
}
}
int main()
{
while(~scanf("%d%d",&n,&m)){
init(n);
for(int i = 0;i<m;i++){
int u,v,w,c;
scanf("%d%d%d%d",&u,&v,&c,&w);
addedge(u,v,w,c);
addedge(v,u,w,c);
}
dijk(1);
printf("%d\n",dis[n]);
}
}
Wormholes POJ - 3259
给一个图,和一些权值为正的边,一些权值为负的边,权值为负的边是单向的,正的是双向的,问你有没有负环,我直接用spfa判断,如果有的点被访问次数大于n次,则说明产生了负环
#include<iostream>
#include<algorithm>
#include<string.h>
#include<string>
#include<queue>
#include<vector>
#include<map>
#define clr(x,b) memset(x,(b),sizeof(x))
#define fuck cout<<"fuck:"<<__LINE__<<endl;
using namespace std;
const int maxn = 100200;
const int maxm = 100200;
int n,m,w;
int ct = 0;
int dis[maxn];
bool inq[maxn];
int head[maxn];
int num[maxn];
struct edge{
int to;
int len;
int next;
}E[maxm];
struct node{
int x;
int dis;
bool operator < (const node b)const{
return dis<b.dis;
}
};
void addedge(int u,int v,int w){
E[ct].to = v;
E[ct].len = w;
E[ct].next = head[u];
head[u] = ct++;
}
bool spfa(){
queue<int>Q;
int st = 1;
dis[st] = 0;
Q.push(st);
inq[st] = true;
num[st]++;
while(!Q.empty()){
int t = Q.front();
Q.pop();
inq[t] = false;
for(int i = head[t];i!=-1;i = E[i].next){
int d = E[i].to;
// if(inq[d])continue;
if(dis[d]>dis[t]+E[i].len){
//fuck
dis[d] = dis[t]+E[i].len;
if(!inq[d]){
inq[d] = true;
Q.push(d);
num[d]++;
if(num[d]>n)return true;
}
}
}
}
return false;
}
int main(){
int T;
cin>>T;
while(T--){
clr(head,-1);
ct = 0;
clr(dis,0x3f3f3f3f);
clr(num,0);
clr(inq,0);
cin>>n>>m>>w;
for(int i = 0;i<m;i++){
int u,v,l;cin>>u>>v>>l;
addedge(u,v,l);
addedge(v,u,l);
}
for(int i = 0;i<w;i++){
int u,v,l;cin>>u>>v>>l;
addedge(u,v,-l);
}
if(spfa())cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
//fuck
}
飞行路线 HYSBZ - 2763
分层最短路 , 假设如果可以选择k个路,我们就想象有(k+1)个平行宇宙,每个平行宇宙的图是一样的,平行宇宙相邻两层之间的边权值为0,每次决定是否选择这条边,就意味着从这一层到达上一层,最后输出(k+1)个平行宇宙中的最小值即可,具体看建图那一块的代码
#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <functional>
#include <algorithm>
#include <queue>
#include <stdio.h>
#define INF 0x7f7f7f7f
using namespace std;
const int maxn = 110020;
const int maxm = 1100020;
int ct = 0;
int ans;
int n,m,s,t,k;
int head[maxn];
int dis[maxn];
int stt[maxn];
struct Edge{
int v , w ,next;
}edge[2*maxm];
struct node{
int x;
int dis;
bool operator < (const node b)const{
return dis > b.dis;
}
};
void init(int n)
{
for(int i = 0;i<=n;i++)head[i] = -1 ,dis[i] = INF ;
ct = 0;
}
void addedge(int u,int v,int w)
{
edge[ct].v = v;
edge[ct].w = w;
edge[ct].next = head[u];
head[u] = ct++;
}
void dijk(int now)
{
node st;
st.x = now;
st.dis = 0;
dis[now] = 0;
priority_queue<node>Q;
Q.push(st);
while(!Q.empty())
{
node t = Q.top();
Q.pop();
// cout << t.x << endl;
if(dis[t.x] != t.dis)continue;
for(int i = head[t.x];~i;i = edge[i].next)
{
int to = edge[i].v;
if(dis[t.x] + edge[i].w < dis[to]){
dis[to] = dis[t.x] + edge[i].w;
Q.push((node){to,dis[to]});
}
}
}
}
int main()
{
while(~scanf("%d%d%d",&n,&m,&k)){
init((k+1)*(n));
scanf("%d%d",&s,&t);
for(int i = 0;i<m;i++)
{
int u,v,w;
scanf("%d%d%d" , &u,&v,&w);
for(int j = 0;j<=k;j++)
{
addedge(u + j*n , v+j*n , w);
addedge(v + j*n , u+j*n , w);
if(j){
addedge(u+(j-1)*n , v+j*n , 0);
addedge(v+(j-1)*n , u+j*n , 0);
}
}
}
dijk(s);
int mn = INF;
for(int i = 0;i<=k;i++){
//cout << dis[t + i*n] << endl;
mn = min(mn , dis[t + i*n]);
}
printf("%d\n" , mn);
}
}