ACM-ICPC 2018 北京网络赛:K-Dimensional Foil II 一题多解

博客目录

原题

题目链接

#1835 : K-Dimensional Foil II

时间限制:1000ms

单点时限:1000ms

内存限制:256MB

描述

"K-Dimensional Foil" is a dimensional weapon. Its function is quite easy: It can ascend a region in 3D space to K (K≥3) dimension. One can use it to give the enemy unexpected attack. It was called "The Ultimate Weapon".

--"Remembrance of Mars's Past"

You are the chief technology officer in the space fleet, and your fleet was just suffered from the attack of the K-Dimensional Foil. The good news was that you have found the key parameter K, the dimension of the space. But staying in high dimensional space is very dangerous, you must destroy the K-Dimensional Foil as fast as possible.

You have n spaceships, spaceship i locates at si = (si,1, …, si,K), and the K-Dimensional  Foil is a 1-norm ball with center c = (c1, …, cK) and radius r, a 1-norm ball with center c and radius r is a point set defined as
{x |  d(x, c)  ≤ r}, d(x, c) =∑| xi - ci |

In the formula above, the coordinate of point x is (x1, x2 … xK)

Your spaceships will fire laser cannon to destroy the K-Dimensional Foil. The energy decay is very quick with the increase of the distance in the high dimensional space, so for every spaceship, you want to find the closest point (in Euclidean distance) on the K-Dimensional Foil. It's guaranteed that no spaceship is in the K-Dimensional Foil initially.

输入

The first line of the input is an integer T (T ≤ 100), the number of the test cases.

For each test case, the first line contains two integer n, K (1 ≤ n ≤ 50, 1 ≤ K ≤ 100), the number of spaceship in your fleet and the dimension of the space.

Then one line contains an integer r (1 ≤ r ≤ 104 ), the radius of the K-Dimensional Foil.

Then one line contains K integers c1, … cK, meaning the coordinate of the center of the K-Dimensional Foil.

Then n lines follow. Each line contains K integers si,1, …, si,K, meaning the coordinate of a spaceship.

All the absolute values of the coordinate are smaller than 104.

输出

For each test case, output n lines. The ith line contains K numbers representing the coordinate of the closest point on the K-Dimensional Foil to the ith spaceship. The absolute error between your output and the answer should be less than 10-4

提示

The K-Dimensional Foil in the sample was a square with vertex: (1,0), (0,1), (-1,0), (0,-1)

This problem is special judged.

样例输入

1
2 2
1
0 0
1 1
1 3

样例输出

0.50 0.50
0.00 1.00

思路一:越界降维

(注意一范数的意思是取绝对值再求和,所以多维平面不是我们平时的平方的球,而是一次的菱形(比如二维的是|x|+|y|=r))

直线的参数方程(一个点和方向向量:)

求一个点到平面的投影:

我们为了简化计算,可以将坐标平移置圆心在0点。根据对称性再将飞船坐标取绝对值转化到第一象限。最后再转化回来即可

然后对于有些坐标求出来是负数,说明这个维度的极值为0,(第一象限最小值为0而不是负数),然后我们就确定了这个维度为0,降一维之后从头重新解方程,直到所有坐标算出来不为负数即可,然后转化回来坐标输出。

思路二、贪心二分代替方程,不用降维

实际上我们贪心的去想:对于下式

                                                                          S=\sum\limits_{i=1}^Na_i^2

如果我们有这么一种操作可以把某个a_i减一,现在问一次操作后S的最小值,

那么很容易便可以知道我们肯定是去找最大的那个去减一,最后的结果才会最小.

对于这道题其实也一样,我们肯定也是选相对于圆心数值的差(加绝对值)大的维度优先去减小,这样一直贪心下去,

最后落到上面的点肯定就是我们要求的点。

对于这样一种操作,我们可以发现,在经过若干次操作后,这k个维度的向量的长度的最大的那几个肯定数值是相等的,

这是由于我们贪心的选取最大的去减所导致的,由于我们每次减的数值很小,误差小于题目中给的1e-4,那么对于结果来说数值就是无误的.

这样一来,对于这么些操作我们便可以用二分去替代,二分我们最后划定的那个最大值的数值便可以解决此问题。

AC代码一

#include<bits/stdc++.h>
#include<cstring>
using namespace std;
typedef long long ll;
typedef long double lb;
int const maxn=105;
lb ori[maxn],p[maxn];
int s[maxn];
lb ans[maxn];
bool f[maxn];
lb aim[maxn];
int main(){
    #ifndef ONLINE_JUDGE
    freopen("r.txt","r",stdin);
    #endif 
    int T,n,k,r,t;
    cin>>T;
    lb sum;
    while(T--){
        scanf("%d%d",&n,&k);
        scanf("%d",&r);s
        for(int i=0;i<k;i++){
            scanf("%d",&t);
            ori[i]=t; 
        } 
        while(n--){
            for(int j=0;j<k;j++){
                scanf("%d",&t);
                p[j]=t-ori[j];
                s[j]=p[j]>0?1:-1;
                p[j]=abs(p[j]);
            }
            sum=-r;
            for(int j=0;j<k;j++){
                sum+=p[j];
            }
            int dim=0;
            lb len,ab;
            bool flag=0;
            memset(f,0,sizeof(f));
            while(dim<k){
                len=sum/(k-dim);
                flag=0;
                for(int j=0;j<k;j++){
                    if(!f[j]){
                        aim[j]=p[j]-len;
                        if(aim[j]<0){
                            aim[j]=0;
                            f[j]=1;
                            sum-=p[j];
                            dim++;
                            flag=1;
                            break;
                        }
                    }
                }
                if(flag==0){
                    break;
                }
            }
            for(int j=0;j<k;j++){
                printf("%.4Lf ",aim[j]*s[j]+ori[j]);
            }
            printf("\n");
        }
    } 
}

AC代码二

#include<bits/stdc++.h>
using namespace std;
double eps=1e-6;
double c[105],s[105];
double conv[105];
double ans[105];
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int n,k,r;
        scanf("%d%d",&n,&k);
        scanf("%d",&r);
        for(int i=1;i<=k;i++) scanf("%lf",&c[i]);
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=k;j++) scanf("%lf",&s[j]),conv[j]=abs(s[j]-c[j]);
            double L=0,R=1e8;
            while(L<R-eps)  
            {
                double mid=(L+R)/2.0;
                double sum=0;
                for(int j=1;j<=k;j++) sum+=max(0.0,conv[j]-mid);
                if(sum<=r) R=mid;
                else L=mid;
            }
            for(int j=1;j<=k;j++)
            {
                if(conv[j]>=R) conv[j]=R;
                if(s[j]>c[j]) ans[j]=-conv[j]+s[j];
                else ans[j]=conv[j]+s[j];
                printf("%.5f ",ans[j]);
            }
            printf("\n");
        }
    }
}
 

猜你喜欢

转载自blog.csdn.net/GreyBtfly/article/details/82824043