HDU 4183 Pahom on Water
Pahom on Water is an interactive computer game inspired by a short story of Leo Tolstoy about a poor man who, in his lust for land, forfeits everything. The game's starting screen displays a number of circular pads painted with colours from the visible light spectrum. More than one pad may be painted with the same colour (defined by a certain frequency) except for the two colours red and violet. The display contains only one red pad (the lowest frequency of 400 THz) and one violet pad (the highest frequency of 789 THz). A pad may intersect, or even contain another pad with a different colour but never merely touch its boundary. The display also shows a figure representing Pahom standing on the red pad.
The game's objective is to walk the figure of Pahom from the red pad to the violet pad and return back to the red pad. The walk must observe the following rules:
1.If pad α and pad β have a common intersection and the frequency of the colour of pad α is strictly smaller than the frequency of the colour of pad β, then Pahom figure can walk from α to β during the walk from the red pad to the violet pad
2. If pad α and pad β have a common intersection and the frequency of the colour of pad α is strictly greater than the frequency of the colour of pad β, then Pahom figure can walk from α to β during the walk from the violet pad to the red pad
3. A coloured pad, with the exception of the red pad, disappears from display when the Pahom figure walks away from it.
The developer of the game has programmed all the whizzbang features of the game. All that is left is to ensure that Pahom has a chance to succeed in each instance of the game (that is, there is at least one valid walk from the red pad to the violet pad and then back again to the red pad.) Your task is to write a program to check whether at least one valid path exists in each instance of the game.
Input
The input starts with an integer K (1 <= K <= 50) indicating the number of scenarios on a line by itself. The description for each scenario starts with an integer N (2 <= N <= 300) indicating the number of pads, on a line by itself, followed by N lines that describe the colors, locations and sizes of the N pads. Each line contains the frequency, followed by the x- and y-coordinates of the pad's center and then the radius. The frequency is given as a real value with no more than three decimal places. The coordinates and radius are given, in meters, as integers. All values are separated by a single space. All integer values are in the range of -10,000 to 10,000 inclusive. In each scenario, all frequencies are in the range of 400.0 to 789.0 inclusive. Exactly one pad will have a frequency of “400.0” and exactly one pad will have a frequency of “789.0”.
Output
The output for each scenario consists of a single line that contains: Game is VALID, or Game is NOT VALID
Sample Input
2
2
400.0 0 0 4
789.0 7 0 2
4
400.0 0 0 4
789.0 7 0 2
500.35 5 0 2
500.32 5 0 3
Sample Output
Game is NOT VALID
Game is VALID
题意:判断能否从起点走到终点再走回来(相当于判断从起点到终点是否有两条完全不同的简单路径)。
从起点出发时,只能从低频圈往高频圈走,且只能走向与当前圈有交点的圈,除始末圈外,走过的圈都要删掉;从终点出发时,只能从高频往低频走,其他规则同前所述。
建边时,只在有交点的两个圈之间,从低频圈向高频圈引边,权值都为1;
最后判断始末点间最大流是否>=2即可。
#include <cstdio>
#include <cstring>
#include <climits>
#include <algorithm>
#define maxn 10100
using namespace std;
int head[maxn],cnt,ans;
int gap[maxn],curedge[maxn],d[maxn],pre[maxn];
// gap:统计高度数量数组,d:距离标号数组;
// curedges:当前弧数组;pre:前驱数组
typedef struct{
int cap,to;
int next;
}node;
node edge[100000];
typedef struct{
double f;
int x,y,r;
}input;
input in[maxn];
bool cmp(input x,input y){
if(x.f<y.f)
return true;
return false;
}
void initi(){
memset(d,0,sizeof(d));
memset(gap,0,sizeof(gap));
memset(pre,-1,sizeof(pre));
memset(head,-1,sizeof(head));
ans=0;//初始化最大流为0
cnt=0;
}
void addedge(int a,int b,int c){//有向图加边
edge[cnt].to=b,edge[cnt].cap=c;
edge[cnt].next=head[a],head[a]=cnt++;
edge[cnt].to=a,edge[cnt].cap=0;
edge[cnt].next=head[b],head[b]=cnt++;
}
int max_flow(int start,int end,int n){
int i,u,tmp,neck;
for(i=1;i<=n;i++)
curedge[i]=head[i];//初始化当前弧为第一条邻接边
gap[0]=n;
u=start;
while(d[start]<n){//当d[start]>=n,网络中肯定出现了gap
if(u==end){//增广成功,寻找瓶颈边
int min_flow=INT_MAX;
for(i=start;i!=end;i=edge[curedge[i]].to){
if(min_flow>edge[curedge[i]].cap){
neck=i;
min_flow=edge[curedge[i]].cap;
}
}
for(i=start;i!=end;i=edge[curedge[i]].to){//更新边与回退边的流量//****
tmp=curedge[i];
//edge[tmp].cap=0;
//edge[tmp^1].cap=0;
edge[tmp].cap-=min_flow;
edge[tmp^1].cap+=min_flow;//^1:偶数+1,奇数-1
}
ans+=min_flow;
u=neck;//下次增广从瓶颈边开始
}
for(i=curedge[u];i!=-1;i=edge[i].next)
if(edge[i].cap&&d[u]==d[edge[i].to]+1)//寻找可行弧
break;
if(i!=-1){
curedge[u]=i;
pre[edge[i].to]=u;
u=edge[i].to;
}
else{
if(--gap[d[u]]==0)
break;
curedge[u]=head[u];
for(tmp=n,i=head[u];i!=-1;i=edge[i].next)
if(edge[i].cap)
tmp=std::min(tmp,d[edge[i].to]);
d[u]=tmp+1;
++gap[d[u]];
if(u!=start)
u=pre[u];//重标号并且从当前点前驱重新增广
}
}
return ans;
}
bool jud(int i,int j){
if((in[i].x-in[j].x)*(in[i].x-in[j].x)+(in[i].y-in[j].y)*(in[i].y-in[j].y)
<=(in[i].r+in[j].r)*(in[i].r+in[j].r))//判断有交点
return true;
return false;
}
int main(){
int N;
int T;
int i,j,k;
scanf("%d",&T);
while(T--){
initi();
scanf("%d",&N);
for(i=1;i<=N;i++){
scanf("%lf %d %d %d",&in[i].f,&in[i].x,&in[i].y,&in[i].r);
}
sort(in+1,in+1+N,cmp);
//addedge(0,1,1);
for(i=1;i<=N;i++){
for(j=i+1;j<=N;j++){
if(jud(i,j)){
addedge(i,j,1);
}//从低频向高频建边
}
}
int flow;
flow=max_flow(1,N,N);
//printf("%d\n",flow);
if(flow>=2)
printf("Game is VALID\n");
else
printf("Game is NOT VALID\n");
}
return 0;
}