東北林業大NEFU 五一歡樂水題 F&H題解

比賽鏈接

H卡迪亞的遊戲

這題一看,零一揹包的皮,然後無論是回溯做法的O(2^n)還是正常dp的O(VN)都滿足不了這些毒瘤數據,過於生草,然後神勇的隊友竟然設dp[i][j]爲前i個物品價值爲j的情況下的最小重量。時間複雜度一下子變成O(n*價值最大值),才1e4。

代碼:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<cmath>
using namespace std;
typedef long long ll;
const int mod=1e9+7;
const int inf=0x3f3f3f3f; 
int w[105],v[105];
int dp[105][10005];
int main(){
	int n,W;
	scanf("%d %d",&n,&W);
	for (int i=1;i<=n;i++)
		scanf("%d %d",&w[i],&v[i]);	
	for (int i=0;i<=n;i++)
		for (int j=0;j<=n*100;j++)
			dp[i][j]=inf;
	dp[0][0]=0;
	for(int i=1;i<=n;i++){
        for(int j=0;j<=n*100;j++)
            dp[i][j]=min(dp[i-1][j],dp[i-1][j-v[i]]+w[i]);
    }
    int ans=0;
    for(int i=0;i<=n*100;i++)
		if (dp[n][i]<=W) ans=i;
	printf("%d",ans);
}

F我要去看流星雨

這個題可以先找有哪幾對點滿足引力差不大於M的,也可以先找相鄰點;最後來一個並查集求聯通塊就行了。師兄先找後者,他說散列再散列,然後給出華麗的code說:“stl大賽”

師兄的做法和我是殊途同歸的,我先求引力差不超過M的pair,這個求法就很好求了,開一個結構體按照v大小sort一下就行了,用Next數組來標記當前點滿足引力差小於等於M的點區間是多少,因爲代碼有點長就註釋了一下,看註釋問題不大就不細說。

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <climits>
#include <queue>
#include <stack>
#include <map>
//
using namespace std;
const int INF = 0x3f3f3f3f;//1.06e9大小
const int mod1 = 1e9 + 7;
const int mod2 = 998244353;
const int mod3 = 1e9;
const double PI = 3.14159265;
const double eps =1e-8;
typedef unsigned long long ULL;
typedef long long LL;
//
struct note
{
	int x,y,z,v;
};
note a[10001];
int fa[10001];
int Next[10001];
int tong[10001];
bool cmp(note x,note y)
{
	return x.v>y.v;
}

int getfa(int k)
{
	return fa[k]==k?k:fa[k]=getfa(fa[k]);
}

void mer(int x,int y)
{
	int a=getfa(x);
	int b=getfa(y);
	fa[a]=b;
}

bool check(int i,int j)
{
	int cnt=0;
	int flag=0;
	if(a[i].x==a[j].x)++cnt;
	if(a[i].y==a[j].y)++cnt;
	if(a[i].z==a[j].z)++cnt;
	if(abs(a[i].x-a[j].x)==1)flag=1;
	if(abs(a[i].y-a[j].y)==1)flag=1;
	if(abs(a[i].z-a[j].z)==1)flag=1;
	if(cnt==3)return true;
	if(cnt==2&&flag)return true;
	return false;
}

int main()
{
	int n,m;
	cin>>n>>m;
	for(int i=1;i<=n;++i)fa[i]=i;
	for(int i=1;i<=n;++i)
	{
		scanf("%d %d %d %d",&a[i].x,&a[i].y,&a[i].z,&a[i].v);
	}
	sort(a+1,a+1+n,cmp);
	int j=2;
	for(int i=1;i<=n;++i)
	{
		while(j!=n+1&&a[i].v-a[j].v<=m)++j;
		Next[i]=j;//求第i個點i能和(i,j)區間之間的點鏈接.
	}
	for(int i=1;i<n;++i)
	{
		for(int j=i+1;j<Next[i];++j)
		{
			if(check(i,j))mer(i,j);//鏈接所有引力差小於等於m同時相鄰的點。
		}
	}
	int cnt=0;//連通塊的數量;
	int MAX=0;
	for(int i=1;i<=n;++i)
	{
		if(tong[getfa(i)]==0)++cnt;
		tong[getfa(i)]++;
		MAX=max(MAX,tong[getfa(i)]);
	}
	printf("%d %d\n",cnt,MAX);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章