【DP】ants

题目简述: 

平面上有N只蚂蚁,每个蚂蚁的位置我们用一个整数坐标(x,y)表示。现在我们想知道这个平面上可能有几群蚂蚁。我们称一些蚂蚁组成一个群,当且仅当:这个群里任意两只蚂蚁之间的距离,都严格小于这个群里任意一只蚂蚁到不属于这个群的任意一只蚂蚁之间的距离。两只蚂蚁之间的距离为sqrt((x1-x2)^2+(y1-y2)^2)。对重合蚂蚁的特别声明:一只蚂蚁始终可以作为一个群,即可以认为自己到自己距离为-oo,若有4只重合蚂蚁,则答案为1001。


我们思考: 如果按照边权加入边, 若某一时刻若有一个连通块是一个完全图, 那么这个块是可以组成一个群的。

一个思路: 记录当前群数 Gr, 我们不断加边进去(相同的边必须一起加进去), 不断减小Gr, 当某一个时刻这个图是稳定的(每个连通块单独成群) 那么ans[Gr]= 1。

显然这是不行的。

但我们考虑, 如果一个群 G 是由 G1 + G2 组成的, 群F 是由 F1 + F2 组成的(F1 , F2, G1, G2都是可以单独成群) , 那么 群数有可能为 2, 3, 4.

若G1 - G2,   F1  - F2同时合并, 如果按照上面的思路, Gr将直接-2, 所以 3 这种情况将直接忽略。


所以对于一个连通块, 我们记录一个数组, 表示这个群可以由几个群构成的。

每次合并, 只要合并背包就行了。


Pro:

#include<cstdio>
#include<cstring>
#include<set>
#include<string>
#include<algorithm>
#include<ctime>
#define sett set<int>::iterator

using namespace std;

struct pa{int x,y,l;} p[5010],dis[1000010];

bool ans[5010];

int n,fa[5010],tot,size[5010],maxl[5010],nn[1000010],num;

set<int> can[5010],node[5010];

bool cmp(pa a,pa b) {return a.l<b.l;}

int sqr(int x) {return x*x;}

int getfa(int x){if (fa[x]!=x) fa[x]=getfa(fa[x]); return fa[x];}

void update(int &a,int b){if (b>a) a=b;}

int Dis(int i,int j){return sqr(p[i].x-p[j].x)+sqr(p[i].y-p[j].y);}

int main()
{
	freopen("ant.in","r",stdin); freopen("ant.out","w",stdout);
	for (scanf("%d",&n);n;scanf("%d",&n))
	{
		for (int i=0;i<n;i++) 
        {
            scanf("%d%d",&p[i].x,&p[i].y);
			can[i].clear(),can[i].insert(0);
			fa[i]=i,size[i]=1; maxl[i]=0;
			node[i].clear(); node[i].insert(i);
		}
		tot=0;
		for (int i=0;i<n;i++)
			for (int j=0;j<n;j++) if (i!=j) dis[tot].x=i,dis[tot].y=j,dis[tot++].l=Dis(i,j);
		sort(dis,dis+tot,cmp);
		for (int i=0;i<tot;)
		{
			int j=i;
			num=0;
			for (;j<tot && dis[j].l==dis[i].l;j++)
			{
				int f1=getfa(dis[j].x),f2=getfa(dis[j].y);
				if (f1!=f2)
				{
					set<int> now; now.clear();
					for (sett ii=can[f1].begin();ii!=can[f1].end();ii++)
						for (sett jj=can[f2].begin();jj!=can[f2].end();jj++)
							now.insert((*ii)+(*jj));
					for (sett ii=now.begin();ii!=now.end();ii++) can[f1].insert(*ii);
					now.clear();
					update(maxl[f1],maxl[f2]);
					for (sett ii=node[f1].begin();ii!=node[f1].end();ii++)
						for (sett jj=node[f2].begin();jj!=node[f2].end();jj++)
						update(maxl[f1],Dis(*ii,*jj));
					for (sett jj=node[f2].begin();jj!=node[f2].end();jj++) node[f1].insert(*jj);
					fa[f2]=f1; size[f1]+=size[f2];
				}
				nn[num++]=f1;				
			}
			for (int k=0;k<num;k++)
				if (fa[nn[k]]==nn[k] && maxl[nn[k]]<=dis[i].l) can[nn[k]].insert(size[nn[k]]-1);
			i=j;
		}
		memset(ans,0,sizeof ans);
		for (int i=0;i<n;i++) if (size[i]==n) for (sett j=can[i].begin();j!=can[i].end();j++) ans[n-(*j)]=true;
		for (int i=1;i<=n;i++) if (ans[i]) printf("1");else printf("0");
		puts("");
	}
	return 0;
}


帮我调试和完善下面代码,不要改变变量名和算法: #include<bits/stdc++.h> #define itn int using namespace std; const int MAXN = 105; const int inf = 0x3f3f3f3f; itn N, M; double w[MAXN], p, dp[MAXN][MAXN][40], ans; itn st; void init(){ for( int i = 1; i < MAXN; i ++ ){ for( itn j = 1; j < MAXN; j ++ ){ for( itn k = 1; k < 40; k ++ ){ if( i == j ) continue; dp[i][j][k] = -inf; } } } for( itn i = 1; i <= M; i ++ ){ itn a, b; cin >> a >> b; dp[a][b][0] = w[b] * p; } } int main(){ cin >> N >> M; for( itn i = 1; i <= N; i ++ ){ cin >> w[i]; } cin >> st >> p; init(); for( itn t = 1; t < 30; t ++ ) for( int k = 1; k <= N; k ++ ) for( itn i = 1; i <= N; i ++ ) for( itn j = 1; j <= N; j ++ ){ dp[i][j][t] = max( dp[i][j][t], dp[i][k][t] + dp[k][j][t] * p ); if( i == st ) ans = max( ans, dp[i][j][t] ); } cout << ans; return 0; } 题面:# P4308 [CTSC2011] 幸福路径 题目描述 有向图 G G 有 n n 个顶点 1 , 2 , ⋯   , n 1,2,⋯,n,点 i i 的权值为 w ( i ) w(i)。 现在有一只蚂蚁,从给定的起点 v 0 v 0 ​ 出发,沿着图 G G 的边爬行。开始时,它的体力为 1 1。每爬过一条边,它的体力都会下降为原来的 ρ ρ 倍,其中 ρ ρ 是一个给定的小于 1 1 的正常数。而蚂蚁爬到某个顶点时的幸福度,是它当时的体力与该点权值的乘积。 我们把蚂蚁在爬行路径上幸福度的总和记为 H H。很显然,对于不同的爬行路径, H H 的值也可能不同。小 Z 对 H H 值的最大可能值很感兴趣,你能帮助他计算吗?注意,蚂蚁爬行的路径长度可能是无穷的。 输入格式 每一行中两个数之间用一个空格隔开。 输入文件第一行包含两个正整数 n , m n,m,分别表示 G G 中顶点的个数和边的条数。 第二行包含 n n 个非负实数,依次表示 n n 个顶点权值 w ( 1 ) , w ( 2 ) , ⋯   , w ( n ) w(1),w(2),⋯,w(n)。 第三行包含一个正整数 v 0 v 0 ​ ,表示给定的起点。 第四行包含一个实数 ρ ρ,表示给定的小于 1 1 的正常数。 接下来 m m 行,每行两个正整数 x , y x,y,表示 ( x , y ) (x,y) 是 G G 的一条有向边。可能有自环,但不会有重边。 输出格式 仅包含一个实数,即 H H 值的最大可能值,四舍五入到小数点后一位。 输入输出样例 #1 输入 #1 5 5 10.0 8.0 8.0 8.0 15.0 1 0.5 1 2 2 3 3 4 4 2 4 5 输出 #1 18.0 说明/提示 对于 100 % 100% 的数据, 1 ≤ n ≤ 100 1≤n≤100, 1 ≤ m ≤ 1000 1≤m≤1000, 0 < ρ ≤ 1 − 10 − 6 0<ρ≤1−10 −6 , 0 ≤ w ( i ) ≤ 100 0≤w(i)≤100。
最新发布
10-02
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值