Hoj 13313 Smoking gun 差分约束问题

传送门: http://acm.hnu.cn/online/?action=problem&type=show&id=13313

Smoking gun
Time Limit: 10000ms, Special Time Limit:25000ms, Memory Limit:65536KB
Total submit users: 14, Accepted users: 7
Problem 13313 : No special judgement
Problem description

Andy: ”Billy the Kid fired first!”

Larry: ”No, I’m sure I heard the first shot coming from John!”

The arguments went back and forth during the trial after the big shoot-down, somewhere in the old wild west. Miraculously, everybody had survived (although there were serious injuries), but nobody could agree about the exact sequence of shots that had been fired. It was known that everybody had fired at most one shot, but everything had happened very fast. Determining the precise order of the shots was important for assigning guilt and penalties.

But then the sheriff, Willy the Wise, interrupted: ”Look, I’ve got a satellite image from the time of the shooting, showing exactly where everybody was located. As it turns out, Larry was located much closer to John than to Billy the Kid, while Andy was located just slightly closer to John than to Billy the Kid. Thus, because sound travels with a finite speed of 340 meters per second, Larry may have heard John’s shot first, even if Billy the Kid fired first. But, although Andy was closer to John than to Billy the Kid, he heard Billy the Kid’s shot first ? so we know for a fact that Billy the Kid was the one who fired first!

Your task is to write a program to deduce the exact sequence of shots fired in situations like the above.


Input

On the first line a positive integer: the number of test cases, at most 100. After that per test case:

• one line with two integers n (2 ≤ n ≤ 100) and m (1 ≤ m ≤ 1000): the number of people involved and the number of observations.

• n lines with a string S, consisting of up to 20 lower and upper case letters, and two integers x and y (0 ≤ x,y ≤ 1000000): the unique identifier for a person and his/her position in Cartesian coordinates, in metres from the origin.

• m lines of the form “S1 heard S2 firing before S3”, where S1, S2 and S3 are identifiers among the people involved, and S2 6= S3.

If a person was never mentioned as S2 or S3, then it can be assumed that this person never fired, and only acted as a witness. No two persons are located in the same position.

The test cases are constructed so that an error of less than 10−7in one distance calculation will not affect the output.


Output

Per test case:

• one line with the ordering of the shooters that is compatible with all of the observations, formatted as the identifiers separated by single spaces.

If multiple distinct orderings are possible, output “UNKNOWN” instead. If no ordering is com- patible with the observations, output “IMPOSSIBLE” instead.


Sample Input
3
4 2
BillyTheKid 0 0
Andy 10 0
John 19 0
Larry 20 0
Andy heard BillyTheKid firing before John
Larry heard John firing before BillyTheKid
2 2
Andy 0 0
Beate 0 1
Andy heard Beate firing before Andy
Beate heard Andy firing before Beate
3 1
Andy 0 0
Beate 0 1
Charles 1 3
Beate heard Andy firing before Charles
Sample Output
BillyTheKid John
IMPOSSIBLE
UNKNOWN
Problem Source
HNU Contest 

题目意思:

n个人中的某些人发生一起枪战,police要确开枪人的开枪顺序,若能找到唯一顺序,则输出,若多组顺序则输出UNKNOWN,若无解,则IMPOSSIBLE

先给出n个人的二维平面上的坐标,然后给出m条信息。

A heard B firing before C    表示A先听到B的枪声,然后在听到C的枪声。

首先需要知道的是,只有一部分人开枪了,所有的判断操作都是针对那一部分人进行的。

(a,b,c)对于这样一组信息,若用dis[b][c]表示b比c先dis[b][c]的时间开枪,如果坐标上|ab|确实比|ac|远,那么我可以确定是b先开枪,否则,我不能确定谁先开枪。

最短路原理:(a,b,c)表示a->b有边权值c,那么dis[b]<=dis[a]+c。

此题: dist(b,c)<=dist(a,b)-dist(a,c)   即     dist(a,c)<=dist(a,b)-dist(b,c) 边为b->c权值为-dist(b,c)

那么可以依次考虑差分约束问题,建边dis[b][c]=dist(a,c)-dist(a,b) //取负值是为了Floyd判环,dis[i][i]<0出现负环,无解IMPOSSIBLE

最后确定顺序,找开枪的 i 满足dis[i][j]<0,那么i是先于其他人的,分别先|dist[i][j]|的时间,依次下去,直到找完所有的开枪人。

若个位置不能找到,那么是UNKNOWN

#include<iostream>
#include<cstdio>
#include<cstring>
#include<map>
#include<cmath>
#include<string>
using namespace std;
#define INF 0x3fffffff
map <string,int> mapt;
int n,m;
struct node{
    int id;
    double x,y;
    char name[100];
    node(double x_=0,double y_=0):x(x_),y(y_){}
    void in(){scanf("%lf%lf",&x,&y);}
    node operator - (node a){return node(x-a.x,y-a.y); }
    double dis(){return sqrt(x*x+y*y);}
}p[110];
char s[100];
bool flag[110];
int ans[110];
int cnt;
string str;
void change(){
    str="";
    int len=strlen(s);
    for(int j=0;j<len;j++)
        str=str+s[j];
    str=str+'\0';
}
double dist[110][110];
void floyed(){
    for(int k=1;k<=n;k++)
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                dist[i][j]=min(dist[i][j],dist[i][k]+dist[k][j]);
}
int main(){
    int T;scanf("%d",&T);
    while(T--){
        mapt.clear();
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                dist[i][j]=(i==j)?0:INF;
        for(int i=1;i<=n;i++){
            flag[i]=false;
            scanf("%s",s);
            p[i].in();
            strcpy(p[i].name,s);
            change();
            mapt[str]=i;
            p[i].id=i;
        }
        for(int i=1;i<=m;i++){
            //Andy heard BidoubleyTheKid firing before John
            // a   b  c  ==>   if ab>=ac  b->c = ac-ab  
            scanf("%s",s);    change();
            int a=mapt[str];
            scanf("%s",s);
            scanf("%s",s);    change();
            int b=mapt[str];
            scanf("%s",s);scanf("%s",s);
            scanf("%s",s);    change();
            int c=mapt[str];
            dist[b][c]=min(dist[b][c],(p[a]-p[c]).dis()-(p[a]-p[b]).dis());
            flag[b]=flag[c]=true;
        }
        floyed();
        bool ok=true;
        for(int i=1;i<=n;i++)if(flag[i])if(dist[i][i]<0){ok=false;break;}
        if(ok==false)puts("IMPOSSIBLE");
        else{
            bool judge;
            cnt=0;
            for(int kk=1;kk<=n;kk++){
                for(int i=1;i<=n;i++){
                    if(flag[i]){
                        judge=true;
                        for(int j=1;j<=n;j++){
                            if(i==j)continue;
                            if(flag[j]==false)continue;
                            if(dist[i][j]>=0){
                                judge=false;
                                break;
                            }
                        }
                        if(judge){
                            ans[cnt++]=i;
                            flag[i]=false;
                            break;
                        }
                    }
                }
                if(judge==false)break;
            }
            if(judge==false)puts("UNKNOWN");
            else{
                for(int i=0;i<cnt;i++)
                    printf("%s%c",p[ans[i]].name,i==cnt-1?'\n':' ');
            }
        }
    }
    return 0;
}

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
#define INF 0x3fffffff
struct node{
    char name[110];
    double x,y;
    void in(){scanf("%s%lf%lf",name,&x,&y); }
}p[110];
double dist(node a,node b){return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)); }
char tmp[110];
char s1[110],s2[110],s3[110];
int flag[110];
int order[110];
double dis[110][110];
int main(){
    int T;scanf("%d",&T);
    while(T--){
        int n,m;scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++){
            flag[i]=0;
            for(int j=1;j<=n;j++)
                dis[i][j]=(i==j)?0:INF;
        }
        for(int i=1;i<=n;i++)
            p[i].in();
        for(int i=1;i<=m;i++){
            //Andy heard BidoubleyTheKid firing before John
            scanf("%s%s%s%s%s%s",s1,tmp,s2,tmp,tmp,s3);
            int a,b,c;
            for(int j=1;j<=n;j++){
                if(strcmp(s1,p[j].name)==0)a=j;
                if(strcmp(s2,p[j].name)==0)b=j;
                if(strcmp(s3,p[j].name)==0)c=j;
            }
            dis[b][c]=min(dis[b][c],dist(p[a],p[c])-dist(p[a],p[b]));//¸ºÖµ£¬Åл·
            flag[b]=flag[c]=1;
        }
        for(int k=1;k<=n;k++)
            for(int i=1;i<=n;i++)
                for(int j=1;j<=n;j++)
                    dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
        bool neg=false;
        int tot=0,cnt=0;
        for(int i=1;i<=n;i++){
            if(flag[i]==0)continue;
            tot++;
            if(dis[i][i]<0)neg=true;
        }
        if(neg==true){puts("IMPOSSIBLE");continue; }
        bool judge;
        while(tot--){
            for(int i=1;i<=n;i++){
                if(flag[i]==0)continue;
                judge=true;
                for(int j=1;j<=n;j++){
                    if(i==j)continue;
                    if(flag[j]==0)continue;
                    if(dis[i][j]>=0){
                        judge=false;
                        break;
                    }
                }
                if(judge==true){
                    order[cnt++]=i;
                    flag[i]=0;
                    break;
                }
            }
            if(judge==false)break;
        }
        if(judge==false)puts("UNKNOWN");
        else{
            for(int i=0;i<cnt;i++)
                printf("%s%c",p[order[i]].name,i==cnt-1?'\n':' ');
        }
    }
    return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值