您的位置:首页 > 其它

The 36th ACM/ICPC Asia Regional Chengdu Site —— Online Contest题解

2015-06-02 17:00 477 查看
Hdu4034 Graph

题目大意:一个n×n的图,(i,j)表示从第i个点到第j个点的最短路径,求原来的图最小的边数是多少?

题目解析:任意两点(i,j)的最短路不能超过从(i,k)->(k,j)所有路径之和,如果相等这样的边(i,j)可要可不要(即失效)

乍一看没思路,分析样例很容易发现问题关键,枚举一条最短路,判断是否有其他两条最短路之和与之相等。

坑点:1.(i,j)(i,k)(k,j)没有任何物理上的长短关系,换句话说,k不一定就位于i,j一条最短路径上,所以i,j,k地位相等,要枚举所有边的情况

           2.注意这样两个逻辑:存在一条边(i,j)满足(i,k)(k,j)与他相等,那么这条边就失效了,一条边不能重复失效多次,所以可以开个标记数组解决;存在一条边(i,j)大于(i,k)(k,j)之和,那么这个图就不存在,所以在枚举过程中要遍历所有可能的情况;

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <climits>
#include <map>
#include <vector>
#include <list>
#include <stack>
#include <queue>
#define eps 1e-5
#define pi acos(-1)
#define clr(k,v) memset(k,v,sizeof(k));
using namespace std;
typedef long long ll;
const int maxn=1e6+10;
const int mod=1000000009;
const int SZ = 1<<20;
struct fastio{
char inbuf[SZ];char outbuf[SZ];fastio(){//高速缓存
setvbuf(stdin,inbuf,_IOFBF,SZ);
setvbuf(stdout,outbuf,_IOFBF,SZ);
}}io;

int n;
int edge[110][110];
bool vis[110][110];

int main()
{
//freopen("input.txt","r",stdin);
int T;cin>>T;int kase=1;
while(T--){
int cnt=0;
clr(vis,0);
cin>>n;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++){
cin>>edge[i][j];
if(edge[i][j]) cnt++;
}
bool ok=true;
for(int i=0;i<n&&ok;i++)
for(int j=0;j<n&&ok;j++)
if(j!=i){
for(int k=0;k<n&&ok;k++){
if(k==i||k==j) continue;
if(edge[i][j]>edge[i][k]+edge[k][j]) ok=false;//存在一边满足就false,所有情况都要遍历
else if(!vis[i][j]&&edge[i][j]==edge[i][k]+edge[k][j]) {cnt--;vis[i][j]=1;}//存在一边相等,这一边就失效了,仅且仅失效一次
}
}

if(!ok) {printf("Case %d: impossible\n",kase++);continue;}
else printf("Case %d: %d\n",kase++,cnt);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  ACM