会有这样的题目,数据量较小,给出两点间之间的关系,求最后是否矛盾(并查集:不过那道题还没有弄懂),或者求出一共有几层关系(火车排队:拓扑排序最长路),以及求出所有能够满足的关系
简单来说:这里我们要求求出所有的关系,通过已给出的关系。
题目:POJ-3660
要求判断给出的点是否能确立和其他的点的大小关系,通过已给出的大小关系。
可以floyd求解:
做法一:先读入关系,但必须是有向边,否则处理会有误。然后跑一遍Floyd,松弛操作具体为两条小路皆合法才合法。最后判断的时候,因为求的是
>
>
>关系,所以还判断一下是否存在
<
<
<的关系。
做法二:就是对于每个点,如果是可以知道所有关系的,指向自己的点和自己指向的点一定等于
n
−
1
n-1
n−1。这句话的意思很简单,就是
d
f
s
dfs
dfs子树下的所有结点,正反向建图即可。
这里我只写了做法一解法的代码。仅供参考。
#include<bits/stdc++.h>
#define FOR(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
#define ll long long
int n,m;
const int maxn = 404;
bool d[maxn][maxn];
void floyd(){
for(int i=1;i<=n;i++)d[i][i]=1;
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
d[i][j]=max(d[i][j],d[i][k]&&d[k][j]);
}
int main(){
cin>>n>>m;
memset(d,0,sizeof(d));
FOR(i,1,m){
int x,y;scanf("%d%d",&x,&y);
d[x][y]=1;
}
floyd();
int ans=0;
for(int i=1;i<=n;i++){
int cnt=0;
for(int j=1;j<=n;j++)if(d[i][j]||d[j][i])cnt++;
if(cnt==n)ans++;
}
cout<<ans<<endl;
}
事实上
t
a
r
j
a
n
tarjan
tarjan也可以处理下面这类问题,不过小数据可以用
f
l
o
y
d
floyd
floyd做。
U
v
a
247
Uva247
Uva247
这道题题意,
A
给
B
A给B
A给B打电话,给出多种这样的关系,如果这样能一直传递到某个
Z
Z
Z到
A
A
A,这就是个电话圈。
所以我们可以这样处理:
d
[
i
]
[
j
]
=
d
[
i
]
[
j
]
∣
∣
(
d
[
i
]
[
k
]
d[i][j]=d[i][j]||(d[i][k]
d[i][j]=d[i][j]∣∣(d[i][k]&&
d
[
k
]
[
j
]
)
d[k][j])
d[k][j])
传递闭包。如果最后两者能够互相传递即是答案。(a能到达b,b也要可以回到a)所以即使闭包(有向环)
#include<bits/stdc++.h>
#define FOR(i,a,b) for(int i=a;i<=b;i++)
#define ll long long
#define ull unsigned long long
using namespace std;
const int maxn = 100;
int n,m;
int d[maxn][maxn];
int flag[maxn];
map<string,int>M;
vector<int>G[maxn];
string A[maxn];
int main(){
int cnt,a,b;
int kase=0;
while(cin>>n>>m){
if(n==0&&m==0)break;
cnt=0;
M.clear();
memset(d,0,sizeof(d));
memset(flag,0,sizeof(flag));
FOR(i,1,n)G[i].clear();
string str;
FOR(i,1,m){
cin>>str;
if(!M[str])a=M[str]=++cnt;
else a=M[str];
A[a]=str;
cin>>str;
if(!M[str])b=M[str]=++cnt;
else b=M[str];
A[b]=str;
d[a][b]=1;
}
for(int i=1;i<=n;i++)d[i][i]=1;
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++){
d[i][j]=d[i][j]||(d[i][k]&&d[k][j]);
}
if(kase)puts("");
printf("Calling circles for data set %d:\n",++kase);
string ans="";
for(int i=1;i<=n;i++)if(!flag[i]){
flag[i]=1;
ans="";
for(int j=1;j<=n;j++)if(d[i][j]&&d[j][i]){
ans+=A[j]+", ";
flag[j]=1;
}
if(ans!=""){
for(int j=0;j<ans.size()-2;j++)printf("%c",ans[j]);
}
puts("");
}
}
}