题意:
图中有两种连通关系,一种是is关系,一种是has关系。然后询问你m个问题,每个问题是x y z,表示x和z的关系是y,问你这种描述是否正确。
解法:
在本题中需要搞清楚题意,题意不是很好懂。
基本上题意就是,如果A和B是is关系,那么从A到B的路径上都是is边。
如果A和B是has关系,那么A到B的路径上至少有一条has边。
因此对于题目中给出的描述,如果A和B的关系是is关系,那么从A到B连一条is的边,如果关系是has,则从A到B连一条has边。
由于is关系和has关系的判定方法不一样,因此我们建两个图,一个图中只放is边,一个图中has和is边都放,然后对于不同关系进行不同的判定。
对于is关系,我们要求只有is边的图中两点连通。
对于has关系,我们要求在有所有边的图中两点连通,并且这两点之间的路径上必须有一条has边。
题目解析完了之后,剩下的就是如何求解了。求is关系不难,重点在于求has关系,如何判定两点之间的路径一定有一条has边呢。
两种思路。
第一种思路:最短路
给has边赋值为-1,给is边赋值为0,用Floyd求最短路。如果他们之间的距离小于0,那么说明这两点之间一定有has边。【这里需要注意,在更新最短路的时候可能会爆long long】
第二种思路:bfs【更可取】
给每一个点都有一个vis值,vis == 0,表示该点不可达,vis == 1,表示该点可只用 is 边到达,vis == 2,表示到该点的路径上一定有一条has边。
由此就可以使用在线算法,直接跑bfs求出结果。
总结:
这里需要总结一下,对于这种求两点是否连通的问题,已经不是第一次遇到了。每一次遇到之后第一个想到的解法都是最短路,但是最后最短路要么不可行,要么不优。
因此对于此类连通问题,以后需要第一时间想到bfs,然后加上适当的剪枝以及一些标记,实现目标。
代码【最短路】:
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <map>
#define rep(i,a,b) for(ll i = a;i <= b;i++)
using namespace std;
const int N = 1000;
typedef long long ll;
const ll inf = 0x3f3f3f3f;
ll d1[N][N],d2[N][N];
ll n,m;
map<string,int> mp;
string s1,s2,s3;
string base1 = "is-a";
string base2 = "has-a";
ll get(string x)
{
if(mp[x] != 0) return mp[x];
mp[x] = ++n;
return mp[x];
}
void Floyd()
{
rep(k,1,n)
rep(i,1,n)
rep(j,1,n)
if(d1[i][j] > d1[i][k]+d1[k][j]){
d1[i][j] = (ll)d1[i][k]+(ll)d1[k][j];
if(d1[i][j] < 0) d1[i][j] = -1;
}
rep(k,1,n)
rep(i,1,n)
rep(j,1,n)
if(d2[i][j] > d2[i][k]+d2[k][j]){
d2[i][j] = (ll)d2[i][k]+(ll)d2[k][j];
}
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
ll T;
while(cin>>T>>m)
{
n = 0;
mp.clear();
rep(i,0,N-1)
rep(j,0,N-1){
d1[i][j] = inf;
d2[i][j] = inf;
}
rep(i,0,N-1) d1[i][i] = d2[i][i] = (ll)0;
rep(i,1,T)
{
cin>>s1>>s2>>s3;
int x = get(s1), y = get(s3);
if(s2 == base1) //is
{
d1[x][y] = min(d1[x][y],(ll)0);
d2[x][y] = min(d2[x][y],(ll)0); //只有is
}
else{
d1[x][y] = (ll)-1;
}
}
Floyd();
rep(i,1,m)
{
cin>>s1>>s2>>s3;
int xp = get(s1);
int yp = get(s3);
if(s2 == base1) //is
{
if(d2[xp][yp] == 0) cout<<"Query "<<i<<": true"<<endl;
else cout<<"Query "<<i<<": false"<<endl;
}
else{
if(d1[xp][yp] >= 0) cout<<"Query "<<i<<": false"<<endl;
else cout<<"Query "<<i<<": true"<<endl;
}
}
}
return 0;
}
代码:【bfs】
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <queue>
#include <map>
#define rep(i,a,b) for(int i = a;i <= b;i++)
using namespace std;
const int N = 1000;
const int M = 5*1e4+1000;
struct Edge{
int to,next,w;
}e1[M],e2[M];
int head1[N],head2[N],tot1,tot2,n,m,vis[N];
map<string,int> mp;
string s1,s2,s3;
string base1 = "is-a";
string base2 = "has-a";
queue<int> q;
void init()
{
n = 0;
tot1 = tot2 = 1;
rep(i,0,505) head1[i] = head2[i] = 0;
}
void add1(int x,int y,int w)
{
e1[++tot1].to = y, e1[tot1].next = head1[x], head1[x] = tot1, e1[tot1].w = w;
}
void add2(int x,int y,int w)
{
e2[++tot2].to = y, e2[tot2].next = head2[x], head2[x] = tot2, e2[tot2].w = w;
}
int get(string x)
{
if(mp[x] != 0) return mp[x];
mp[x] = ++n;
return mp[x];
}
void bfs1(int s)
{
rep(i,0,n) vis[i] = 0;
//vis = 1:只有is,vis = 2:有has
while(q.size()) q.pop();
q.push(s);
vis[s] = 1;
while(q.size())
{
int x = q.front();
q.pop();
for(int i = head1[x]; i ; i = e1[i].next)
{
int y = e1[i].to;
int z = e1[i].w;
if(vis[y] == 2) continue;
else if(vis[y] == 1 && (z == 2 || vis[x] == 2))
{
vis[y] = 2;
q.push(y);
}
else if(vis[y] == 0)
{
if(z == 2 || vis[x] == 2){
vis[y] = 2;
q.push(y);
}
else{
vis[y] = 1;
q.push(y);
}
}
}
}
}
void bfs2(int s)
{
rep(i,0,n) vis[i] = 0;
while(q.size()) q.pop();
q.push(s);
vis[s] = 1;
while(q.size())
{
int x = q.front();
q.pop();
for(int i = head2[x]; i ; i = e2[i].next)
{
int y = e2[i].to;
if(vis[y]) continue;
vis[y] = 1;
q.push(y);
}
}
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
int T;
while(cin>>T>>m)
{
init();
mp.clear();
rep(i,1,T)
{
cin>>s1>>s2>>s3;
int x = get(s1), y = get(s3);
if(s2 == base1) //add1:has+is add2:is
{
add1(x,y,1);
add2(x,y,1);
}
else add1(x,y,2);
}
rep(i,1,m)
{
cin>>s1>>s2>>s3;
int xp = get(s1);
int yp = get(s3);
if(s2 == base1) //is
{
bfs2(xp);
if(vis[yp] == 1) cout<<"Query "<<i<<": true"<<endl;
else cout<<"Query "<<i<<": false"<<endl;
}
else{ //is+has
bfs1(xp);
if(vis[yp] == 2) cout<<"Query "<<i<<": true"<<endl;
else cout<<"Query "<<i<<": false"<<endl;
}
}
}
return 0;
}