Description

给定n个点,m条边以及k个标记点,要求进行Floyd时只以标记的点为中间点进行松弛操作(每条边边权为1)要求你造出m条边的数据来hack掉这种程序。

Hint

3<=n<=300 , 2<=k<=n2<=k<=n , n-1<=m<=n*(n-1)/2;

Solution

我们只需要任意一点只和非标记点连边就可以了(这样就无法正确更新它到其他点的距离)

具体一下几个细节:

1.判k==n或m>最多可以构出的边maxm;

maxm=(n-1)*(n-2)/2+num;(num:非标记点的数量)

2.将随便一个标记点与所以非标记点连边;

3.再随便一个非标记点与未加入图中的点连边来保证图的联通;

4.最后随便加未加的边使边数凑够m即可;

The Code

#include<bits/stdc++.h>
#define maxn 310
using namespace std;
int n,m,k,x,num;
bool vis[maxn],iss[maxn][maxn],viss[maxn];
void init(){
    scanf("%d%d%d",&n,&m,&k);
    for(int i=1;i<=n;i++) iss[i][i]=1;
    for(int i=1;i<=k;i++) scanf("%d",&x),vis[x]=1;
    num=n-k;
    int maxx=(n-1)*(n-2)/2+num;
    if(m>maxx||k==n){
        printf("-1");return;
    } 
    int t,tt=1;int calc=0;
    while(!vis[tt]) tt++; 
    viss[tt]=1;
    for(int i=1;i<=n;i++){
        if(!vis[i]){
            t=i;
            viss[t]=1;
            printf("%d %d\n",t,tt);
            iss[t][tt]=iss[tt][t]=1;
            calc++; 
        }
    }
    
    //保证联通 
    for(int i=1;i<=n;i++){
        if(viss[i]) continue;
        printf("%d %d\n",i,t); 
        iss[i][t]=iss[t][i]=1;
        calc++;
        if(calc==m) break;
    }
    
    
    for(int i=1;i<=n;i++){
        if(calc==m) break;
        if(i==tt) continue;
        for(int j=1;j<=n;j++){
            if(j==tt) continue;
            if(iss[i][j]) continue;
            printf("%d %d\n",i,j);
            calc++;
            iss[i][j]=iss[j][i]=1;
            if(calc==m) break;
        }
    }
}
int main(){
    init();
    
    return 0;
}
Last modification:February 15th, 2019 at 09:29 pm