zoukankan      html  css  js  c++  java
  • FZOJ 2331 LYK loves graph

    魔改最小斯坦纳树的题。。。

    首先我们发现颜色太多了非常不好处理,一种套路是随机把这些颜色映射到 (k) 种颜色,随机很多次来保证正确性。最后的正确率大概是:

    [1-(1-frac{k!}{k^k})^C ]

    其中 (C) 为随机次数。

    好了现在我们只有 (kle 7) 种颜色了。考虑类似最小斯坦纳树的设状态:设 (f[i][j][s]) 表示包括第 (i) 行第 (j) 列的状态为 (s) 的连通块的最小代价。然后由于是点权所以方程式要稍微变动一下。

    代码:

    #pragma GCC optimize(2)
    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    #include<random> 
    
    using namespace std;
    
    mt19937 rnd(0); 
    const int N=20,INF=1<<29;
    int dx[10]={0,-1,0,1,0};
    int dy[10]={0,0,1,0,-1};
    int val[N][N],n,m,k,col[N][N],ans=INF,D[N*N],a[N][N],vis[N][N],f[N][N][2000];
    priority_queue <pair<int,pair<int,int> > > q; 
    
    void init()
    {
    	scanf("%d %d %d",&n,&m,&k);
    	for (int i=1;i<=n;i++)
    		for (int j=1;j<=m;j++)
    			scanf("%d",&a[i][j]);
    	for (int i=1;i<=n;i++)
    		for (int j=1;j<=m;j++)
    			scanf("%d",&val[i][j]);
    }
    
    void Dijkstra(int s)
    {
    	memset(vis,0,sizeof(vis));
    	while(!q.empty())
    	{
    		pair<int,int> p=q.top().second;q.pop();
    		if(vis[p.first][p.second])
    			continue;
    		vis[p.first][p.second]=1;
    		for (int i=1;i<=4;i++)
    		{
    			int tx=p.first+dx[i],ty=p.second+dy[i];
    			if(tx<1||ty<1||tx>n||ty>m||col[tx][ty]==-1)
    				continue;
    			if(f[tx][ty][s]>f[p.first][p.second][s]+val[tx][ty])
    			{
    				f[tx][ty][s]=f[p.first][p.second][s]+val[tx][ty];
    				q.push(make_pair(-f[tx][ty][s],make_pair(tx,ty)));
    			}
    		}
    	}
    }
    
    void work()
    {
    	int T=300;
    	while(T--)
    	{
    		for (int i=0;i<n*m;i++)
    			D[i]=rnd()%k;
    		for (int i=1;i<=n;i++)
    			for (int j=1;j<=m;j++)
    				col[i][j]=(a[i][j]!=-1)?D[a[i][j]]:-1;
    		int Max_N=1<<k;
    		for (int i=1;i<=n;i++)
    			for (int j=1;j<=m;j++)
    				for (int l=0;l<Max_N;l++)
    						f[i][j][l]=INF;
    		for (int i=1;i<=n;i++)
    			for (int j=1;j<=m;j++)
    				if(col[i][j]!=-1)
    					f[i][j][1<<col[i][j]]=val[i][j];
    		for (int s=1;s<Max_N;s++)
    		{
    			for (int i=1;i<=n;i++)
    				for (int j=1;j<=m;j++)
    				{
    					if(col[i][j]==-1) continue;
    					for (int sub=(s-1)&s;sub;sub=(sub-1)&s)
    						f[i][j][s]=min(f[i][j][sub]+f[i][j][s^sub]-val[i][j],f[i][j][s]);
    					if(f[i][j][s]!=INF)
    						q.push(make_pair(-f[i][j][s],make_pair(i,j)));
    				}
    			Dijkstra(s);
    		}
    		for (int i=1;i<=n;i++)
    			for (int j=1;j<=m;j++)
    				ans=min(ans,f[i][j][Max_N-1]);
    	}
    	printf("%d
    ",ans==INF?-1:ans);
    }
    
    int main()
    {
    	init();
    	work();
    	return 0;
    }
    
    由于博主比较菜,所以有很多东西待学习,大部分文章会持续更新,另外如果有出错或者不周之处,欢迎大家在评论中指出!
  • 相关阅读:
    【转载】高内聚低耦合
    【转载】locate命令的使用
    【转载】C内存对齐
    【原创】_INTSIZEOF 内存按照int对齐
    【转载】free查看内存
    Hive查询Join
    Hive数据查询
    Hive导入数据
    Hive表的修改Alter
    Hive中排序和聚集
  • 原文地址:https://www.cnblogs.com/With-penguin/p/13308965.html
Copyright © 2011-2022 走看看