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;
}



發佈了138 篇原創文章 · 獲贊 1 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章