最近的題解的故事背景割。
題目:
描述
在靠近南極的某處,一些企鵝站在許多漂浮的冰塊上。由於企鵝是羣居動物,所以它們想要聚集到一起,在同一個冰塊上。企鵝們不想把自己的身體弄溼,所以它們在冰塊之間跳躍,但是它們的跳躍距離有一個上限。
隨着氣溫的升高,冰塊開始融化,並出現了裂痕。而企鵝跳躍的壓力,使得冰塊的破裂加速。幸運的是,企鵝對冰塊十分有研究,它們能知道每塊冰塊最多能承受多少次跳躍。對冰塊的損害只在跳起的時候產生,而落地時並不對其產生傷害。
現在讓你來幫助企鵝選擇一個冰面使得它們可以聚集到一起。
輸入
第一行一個正數:數據個數,最多100個。之後:
第一行整數N,和浮點數D,表示冰塊的數目和企鵝的最大跳躍距離。
(1≤N ≤100) (0 ≤D ≤100 000),
接下來N行,xi, yi, ni and mi,分別表示冰塊的X和Y座標,該冰塊上的企鵝數目,以及還能承受起跳的次數。
輸出
每個數據:
輸出所有可能的相聚冰塊的編號,以0開始。如果不能相遇,輸出-1。
樣例輸入
2
5 3.5
1 1 1 1
2 3 0 1
3 5 1 1
5 1 1 1
5 4 0 1
3 1.1
-1 0 5 10
0 0 3 9
2 0 1 1
樣例輸出
1 2 4
-1
攢的有點多先寫一道。
簡單點說:網絡流的題,自己建一個源點,源點連向每個冰塊,容量爲該冰塊企鵝數。
冰塊分爲入點和出點,入點到出點容量爲起跳次數。
一個冰塊能跳到另一個冰塊,則前者出點連後者入點,容量INF,後者出點連前者入點,容量INF。
枚舉匯點。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const int maxn=205;
const int INF=214748364;
struct{
int next;
int to;
int w;
int cun;
}edge[maxn*maxn];
int head[maxn],cnt=-1;
void add(int u,int v,int w){//u起點v終點w容量
cnt++;
edge[cnt].to=v;
edge[cnt].w=w;
edge[cnt].next=head[u];
edge[cnt].cun=w;
head[u]=cnt;
}
int lev[maxn],cur[maxn];//lev層數,cur[i]爲以i爲起點的邊的編號
bool bfs(int m,int zong){//m爲匯點,有zong個點
int dui[zong+1],r=0;//隊列和右指針
for(int i=1;i<=zong;i++){//初始化
lev[i]=-1;
cur[i]=head[i];
}
dui[0]=1,lev[1]=0;
int u,v;//u起點v終點
for(int l=0;l<=r;l++){//左指針
u=dui[l];
for(int e=head[u];e!=-1;e=edge[e].next){
v=edge[e].to;
if(edge[e].w>0&&lev[v]==-1){//1.能走 2.未分層
lev[v]=lev[u]+1;
r++;
dui[r]=v;//v入隊
if(v==m)return 1;//分層完畢
}
}
}
return 0;//無法分層
}
int dinic(int u,int flow,int m){//u當前點,flow爲下面的點能夠分配多大的流量,m終點
if(u==m)return flow;//終點直接全流入
int res=0,delta;//res實際流量
for(int &e=cur[u];e!=-1;e=edge[e].next){//'&'相當於cur[u]=e;即流滿的邊不會再被掃一次
int v=edge[e].to;
if(edge[e].w>0&&lev[u]<lev[v]){//只能從低層往高層流
delta=dinic(v,min(edge[e].w,flow-res),m);
if(delta>0){//如果增廣
edge[e].w-=delta;//正向邊容量減少
edge[e^1].w+=delta;//反向邊仍量增加(暗示退流)
res+=delta;//擴張流量增加
if(res==flow)break;//可流的都流完了,及時跳出
}
}
}
if(res!=flow)lev[u]=-1;//沒流完,說明以後不能從這個點流出任何流量,那就不需要這個點了
return res;
}
double suan(int a1,int b1,int a2,int b2){
return sqrt(pow((a2-a1),2)+pow((b2-b1),2));
}
int a[101],b[101],c[101],e[101];
int main(){
int t;
scanf("%d",&t);
while(t--){
int n;
double d;
int sum=0;
scanf("%d%lf",&n,&d);
for(int i=1;i<=maxn;i++){
head[i]=-1;
}
cnt=-1;
for(int i=1;i<=n;i++){
scanf("%d%d%d%d",&a[i],&b[i],&c[i],&e[i]);
add(i*2,i*2+1,e[i]);
add(i*2+1,i*2,0);
sum+=c[i];
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(i==j)continue;
if(suan(a[i],b[i],a[j],b[j])<=d){
add(i*2+1,j*2,INF);
add(j*2,i*2+1,0);
}
}
}
for(int i=1;i<=n;i++){
if(c[i]!=0){
add(1,i*2,c[i]);
add(i*2,1,0);
}
}
int ok=0;
int first=0;
for(int i=1;i<=n;i++){
int zui=i*2;
int ans=0;
while(bfs(zui,2*n+1)==1){
ans+=dinic(1,INF,zui);
}
if(ans==sum){
if(first!=0)printf(" ");
printf("%d",i-1);//編號以0開始所以-1(纔不是我懶得改了)
first=1;
ok=1;
}
for(int i=0;i<=cnt;i++){
edge[i].w=edge[i].cun;
}
}
if(ok==0)printf("-1");
printf("\n");
}
return 0;
}